Questions D, E, and F in this issue are very interesting. To sum up, I had no idea when doing question E. After thinking about the solution to question F for a long time, I changed the question and found that the DP of $O(nlog^2n)$ is still amazing. . .
D Wide Flip
The meaning of the question is to give a 01 string $S(|S|\leq10^5)$, find the largest $K$, so that each flipped interval is at least $K$, and flipped to a string of 0.
If two points are passed, they can all become 0 or both become 1. Check one side from left to right each time.
int n; char val[maxn]; int num[maxn]; boolcheck(int x) { int cnt = 0; memset(num, 0, sizeof(num)); int end = -1; int st = -1; repp(i, 1, n) { if (val[i] == '1') { st = i; end = i + x - 1; break; } } if (end == -1) { returntrue; } repp(i, st, end) { int now = val[i] - '0'; int op = now ^ (cnt & 1); if (op) { if (i + x - 1>n) returnfalse; cnt++; } } returntrue; } boolcheck2(int x) { int cnt = 0; memset(num, 0, sizeof(num)); int end = -1; int st = -1; repp(i, 1, n) { if (val[i] == '0') { st = i; end = i + x - 1; break; } } if (end == -1) { returntrue; } repp(i, st, end) { int now = '1' - val[i]; int op = now ^ (cnt & 1); if (op) { if (i + x - 1>n) returnfalse; cnt++; } } returntrue; } voidsolve() { scanf("%s", val + 1); n = strlen(val + 1); int le = 1; int ri = n; while (le<ri) { int mid = (le + ri + 1) / 2; if (check(mid) || check2(mid)) { le = mid; } else { ri = mid - 1; } } cout << le; }
E Papple Sort
There is a string $S(|S|\leq 2*10^5)$ with all lowercase characters. Every time the adjacent characters are exchanged, ask how many times at least the exchange is required, and the string becomes a palindrome string.
This kind of problem needs to be simplified, and only the relative positions and solutions of the two pairs of characters are considered.
Considering the relative positions of two pairs of characters, there are the following three situations:
1)A…A…..B…B
2)A…B……..A…B
3)A…B…..B…A
One thing you will find here is that in any of the three situations, A can be on the periphery. That is, (l1, r1) and (l2, r2) when l1 < l2, (l1, r1) must be the peripheral letters. So just swipe from left to right, moving each letter to the outermost position.
char val[maxn]; ll num[maxn]; intlowbit(int x) { return x&(-x); } ll getsum(ll x) { ll ans = 0; while (x>0) { ans += num[x]; x -= lowbit(x); } return ans; } ll add(int x, int v) { int up = maxn - 1; while (x <= up) { num[x] += v; x += lowbit(x); } return x; } int vis[maxn]; int num_char[30]; vector<int>pos[30]; voidsolve() { scanf("%s", val + 1); int len = strlen(val + 1); repp(i, 1, len) { num_char[val[i] - 'a']++; pos[val[i] - 'a'].push_back(i); } int cnt = 0; repp(i, 0, 26) { if (num_char[i] & 1) { cnt++; } } if (cnt >= 2) { puts("-1"); return; } repp(i, 1, len) { add(i, 1); vis[i] = 1; } ll ans = 0; repp(i, 1, len) { if (vis[i] == 0)continue; int p = pos[val[i] - 'a'].back(); pos[val[i] - 'a'].pop_back(); if (p == i) { ans += ((getsum(len) - getsum(i)) >> 1); } else { ans += (getsum(len) - getsum(p)); } vis[i] = 0; vis[p] = 0; add(p, -1); add(i, -1); } printf("%lld\n", ans); }
F Christmas Tree
A chains with a length of at most B are combined into a tree of a specific shape through the method in the figure. The lexicographic order of (A,B) is required to be minimum. Find A and B.
According to the explanation of the problem, it can be regarded as a path that can dye a tree into A color at most, and the length of each path is at most B.
It can be found that only points with odd degrees can be made as endpoints. Therefore, the minimum A is the odd point S/2. In this case, see what the maximum degree of each path can be. Dichotomous B value. Every time you check x, you need to do a tree-shaped DP, because the odd points need to be used as endpoints, so the edge between the fa and x points needs to be put into son for matching. dp[x] represents the length of the upward path from this point. If there are an even number of points in son, then just scan once to the left and right, dp[x]=-1. If there are an odd number of sons, a point needs to be raised, and then another two points are made.
int n; vector<int>edge[maxn]; int dp[maxn]; booldfs(int x, int fa, int up) { vector<int>son; if (edge[x].size() & 1)son.push_back(0); for (int i = 0; i<edge[x].size(); i++) { int to = edge[x][i]; if (to == fa)continue; if (!dfs(to, x, up))returnfalse; if(dp[to] != -1)son.push_back(dp[to] + 1); } sort(son.begin(), son.end()); if (son.size() % 2 == 0) { int st = 0; int en = son.size() - 1; while (st < en) { if (son[st] + son[en] > up) { returnfalse; } st++; en--; } dp[x] = -1; } else { int le = 0; int ri = son.size() - 1; int flag = 1; while (le < ri) { int mid = (le + ri) / 2; int i = 0; int j = son.size() - 1; flag = 1; while (i < j) { if (i == mid)i++; if (j == mid)j--; if (i<j) { if (son[i] + son[j] > up) { flag = 0; break; } else { i++; j--; } } } if (flag) { ri = mid; } else { le = mid + 1; } } if (son[le] > up)returnfalse; int i = 0; int j = son.size() - 1; while (i < j) { if (i == le)i++; if (j == le)j--; if (i<j) { if (son[i] + son[j] > up) { returnfalse; } else { i++; j--; } } } dp[x] = son[le]; } returntrue; } voidsolve() { sa(n); repp(i, 1, n - 1) { int x, y; sa(x), sa(y); edge[x].push_back(y); edge[y].push_back(x); } int cnt = 0; int p = 1; repp(i, 1, n) { if (edge[i].size() & 1) { cnt++; } if (edge[i].size() == 1) { p = i; } } int ans = cnt / 2; int le = 1; int ri = n; while (le < ri) { int mid = (le + ri) / 2; memset(dp, 0, sizeof(dp)); if (dfs(p, -1, mid)) { ri = mid; } else { le = mid + 1; } } cout << ans << " " << le << endl; }