VP CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!)
A. Jagged Swaps
题意:给你一个排列,你每次可以选择一个\(i\), 满足\(a_i > a_{i-1}\) 和 \(a_i > a_{i+1}\),然后交换\(a_i\)和\(a_{i+1}\)。 问能不能给数组升序排列。
显然第一个不能动,所以它一定得是\(1\)。在满足这条件后,我们假设\([1, i]\)已经是升序(不一定是最小的\(i\)个数在里面),那么对于第\(i+1\)个数,如果它大于\(a_i\)我们可以把它接在后面,否则我们让他一直往前移,就类似与冒泡排序,这样我们就对\([1, i + 1]\)进行了排序,于是可得最终可以对\([1, n]\)进行排序。所以如果\(a_1\)等于\(1\),那么YES,否则NO。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
if (a[0] == 1) {
std::cout << "YES\n";
} else {
std::cout << "NO\n";
}
}
B. AB Flipping
题意:给你一个只包含\(AB\)的字符串,你每次可以选择一个\(i\), 满足\(s_i = A, s_{i+1} = B\), 然后交换这两个位置上字符,每个位置只能执行一次交换操作,问最多交换多少次。
最前面的\(A\)和最后面的\(B\)之间的位置都可以执行操作,因为对于第\(i\)个位置,如果他不能操作,那么可以把他后面的\(B\)交换下来,和他操作。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
int l = 0, r = n - 1;
while (l < n && s[l] == 'B') {
++ l;
}
while (r >= 0 && s[r] == 'A') {
-- r;
}
std::cout << std::max(0, r - l) << "\n";
}
C. Matching Arrays
题意:给你两个数组\(a, b\),你要重新排列\(b\),使得\(\sum_{i=1}^{n} a_i > b_i\)正好是\(x\)。
我们给两个数组排好序,那么应该让\(A\)的\([n - x + 1, n]\)个最大的数和\(B\)的\([1, x]\)个最小的数匹配,如果这样还不能匹配\(x\)个,那么没有答案,因为你这些数不能匹配,换一个其他数来肯定也不能匹配。 那么我们接下来要让剩下的\(n - x\)个位置都不匹配,直接让两个数组剩下的数从小到大匹配就行了,因为如果有一个匹配的话,你拿它和比它小的换,换过去的哪个位置的数一定比它小,拿它换比它大的数,这个数依旧比它这个位置上的数大。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<int> a(n), b(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
for (int i = 0; i < n; ++ i) {
std::cin >> b[i];
}
std::sort(b.begin(), b.end());
std::vector<std::pair<int, int> > c;
for (int i = 0; i < n; ++ i) {
c.push_back({a[i], i});
}
std::sort(c.begin(), c.end());
std::vector<int> ans(n);
for (int i = n - m, j = 0; i < n; ++ i, ++ j) {
ans[c[i].second] = b[j];
}
for (int i = 0, j = m; i < n - m; ++ i, ++ j) {
ans[c[i].second] = b[j];
}
int cnt = 0;
for (int i = 0; i < n; ++ i) {
cnt += a[i] > ans[i];
}
if (cnt != m) {
std::cout << "NO\n";
return;
}
std::cout << "YES\n";
for (int i = 0; i < n; ++ i) {
std::cout << ans[i] << " \n"[i == n - 1];
}
}
D. Ones and Twos
题意:给你一个只包含\(1\)和\(2\)的数组,每次会问你有没有一个子数组的和等于\(x\)或着修改一个位置上的数。
应该是这道题变过来的 https://www.luogu.com.cn/problem/P3514
如果有区间的和为\(x\),那么也一定有区间和为\(x-2\),因为假设这个\(x\)这个区间为\([l, r]\),那么如果\(l\)或者\(r\)这个位置是\(2\),显然区间缩小一位和就是\(x-2\),否则两边都是\(1\)那么两边都缩一位一样是\(x-2\)。所以我们只要找最大的奇数和最大的偶数就行。
我们最大的奇数或偶数有一个一定是\(sum_{1n}\),另一个最大的我们只要从两边减去一个奇数就行,于是我们存所有\(1\)的位置,每次找最左边的\(1\)和最右边的\(1\)比较哪边减去的值小,就可以得到另一个最大的数。
点击查看代码
void solve() {
int n, q;
std::cin >> n >> q;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
int sum = std::accumulate(a.begin(), a.end(), 0);
std::set<int> s;
for (int i = 0; i < n; ++ i) {
if (a[i] == 1) {
s.insert(i);
}
}
while (q -- ) {
int op, x, y;
std::cin >> op >> x;;
if (op == 1) {
int max[2] = {};
max[sum & 1] = sum;
if (s.empty()) {
max[~sum & 1] = -1;
} else {
int l = *s.begin() * 2 + 1, r = (n - 1 - *s.rbegin()) * 2 + 1;
max[~sum & 1] = sum - std::min(l, r);
}
if (max[x & 1] >= x) {
std::cout << "YES\n";
} else {
std::cout << "NO\n";
}
} else {
std::cin >> y;
-- x;
s.erase(x);
sum -= a[x];
a[x] = y;
sum += a[x];
if (a[x] == 1) {
s.insert(x);
}
}
}
}
E. Permutation Sorting
题意:给你应该排列,要让所有\(i = a_i\),每次把不满足条件位置上的数拿出来循环右移一下,问\(a_i\)什么时候等于\(i\)。
每个数要去的地方是固定的,我们可以找出来,设\(x\)在\(i\),它的目标是\(j\),那么如果有其他数在\([i, j]\)之间出发,并且目的地也在\([i, j]\)之间,那么\(x\)就可以少移动一位,因为这个数不会堵到他前面了,本来是一位一位移,现在前面少了一位,就可以少走一步。
因为它是一个环,所有我们破环成链,把这个移动序列延长两倍,然后求出每个数的起点和终点,那么就变成对于每个\([x_i, y_i]\),有多少\(x_j > x_i\)并且\(y_j < y_i\)的,我们按\(x\)排序,从大到小做,用树状数组维护\(y\)的前缀和就行。
点击查看代码
struct Fenwick {
int n;
std::vector<int> tr;
Fenwick(int _n) : n(_n) {
tr.assign(_n + 1, 0);
}
void modify(int x, int v) {
for (int i = x; i <= n; i += i & -i) {
tr[i] += v;
}
}
int query(int x) {
int res = 0;
for (int i = x; i ; i -= i & -i) {
res += tr[i];
}
return res;
}
int sum(int l, int r) {
return query(r) - query(l - 1);
}
};
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
-- a[i];
}
std::vector<int> ans(n, 1e9);
std::vector<std::pair<int, int> > b, c;
for (int i = 0; i < n; ++ i) {
if (a[i] == i) {
ans[i] = 0;
} else {
b.push_back({a[i], i});
}
}
int m = b.size();
for (int i = 0; i < m; ++ i) {
b.push_back(b[i]);
}
std::vector<int> val(2 * m + 1), suf(n, 1e9);
std::vector<std::array<int, 3> > Q;
for (int i = 2 * m - 1; i >= 0; -- i) {
if (suf[b[i].first] != 1e9) {
val[i + 1] = suf[b[i].first] - i;
Q.push_back({i + 1, suf[b[i].first] + 1, b[i].first});
}
suf[b[i].second] = i;
}
std::sort(Q.begin(), Q.end(), std::greater<std::array<int, 3> >());
Fenwick tr(2 * m);
for (auto & [l, r, id] : Q) {
ans[id] = r - l - tr.query(r);
tr.modify(r, 1);
}
for (int i = 0; i < n; ++ i) {
std::cout << ans[i] << " \n"[i == n - 1];
}
}