[Competition Links]
[Problem Solution Link]
**[A]**Oh Those Palindromes
[Points of Thought]
- A necessary condition for a string to be a palindrome string is that the first character of the string is the same as the last character.
- Therefore, the number of occurrences of the character xxx is cntxcnt_xcntx, and the upper bound of the number of palindrome substrings of a string is I = a Z (cnt I + 12) sum {i = a} {z} \ binom {cnt_i + 1} {2} I = a Z (2cnt I + 1). The upper bound can be obtained directly by sorting all the characters of a string.
- So sort the string and output it.
- Time complexity O(NLogN)O(NLogN)O(NLogN).
[Code]
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } char s[MAXN]; int main() { int n; read(n); scanf("%s", s + 1); sort(s + 1, s + n + 1); printf("%s\n", s + 1); return 0; }
**[B]**Labyrinth
[Points of Thought]
- Assuming that the starting point of a path is (sx,sy)(sx,sy)(sx,sy), and the ending point is (tx, ty) (tx, ty), the number of steps to the left is a a A and the number of steps to the right is B B b, then b_a=ty_sy B-a=ty-sy b_a=ty_sy, which means that b_a B-A b_a is a fixed value. Therefore, a path to minimize a+b a+b also minimizes a a A and B B b, respectively.
- BFSBFSBFS is applied to each pair of edges with the length of 1000 and 111, and then the points whose movement times exceed the standard are eliminated.
- Time complexity O(N2)O(N^2)O(N2).
[Code]
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e3 + 5; const int MAXQ = 8e6 + 5; const int MIDQ = 4e6 + 2; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } char mp[MAXN][MAXN]; int x[MAXQ], y[MAXQ], ml[MAXQ], mr[MAXQ]; int main() { int n, m; read(n), read(m); int l = MIDQ, r = MIDQ; read(x[MIDQ]), read(y[MIDQ]); read(ml[MIDQ]), read(mr[MIDQ]); for (int i = 1; i <= n; i++) scanf("%s", mp[i] + 1); mp[x[MIDQ]][y[MIDQ]] = '*'; int ans = 0; while (l <= r) { int nx = x[l], ny = y[l], tx, ty; ans++; int nml = ml[l], nmr = mr[l++]; tx = nx - 1, ty = ny; if (mp[tx][ty] == '.') { l--, x[l] = tx, y[l] = ty; ml[l] = nml, mr[l] = nmr; mp[tx][ty] = '*'; } tx = nx + 1, ty = ny; if (mp[tx][ty] == '.') { l--, x[l] = tx, y[l] = ty; ml[l] = nml, mr[l] = nmr; mp[tx][ty] = '*'; } tx = nx, ty = ny - 1; if (nml != 0 && mp[tx][ty] == '.') { r++, x[r] = tx, y[r] = ty; ml[r] = nml - 1, mr[r] = nmr; mp[tx][ty] = '*'; } tx = nx, ty = ny + 1; if (nmr != 0 && mp[tx][ty] == '.') { r++, x[r] = tx, y[r] = ty; ml[r] = nml, mr[r] = nmr - 1; mp[tx][ty] = '*'; } } printf("%d\n", ans); return 0; }
**[C]**Dwarves, Hats and Extrasensory Abilities
[Points of Thought]
- It is advisable to divide black spots on the left and white spots on the right.
- Let the current intermediate interval be [l,r][l,r][l,r], mid = L + r2mid= frac {l + r} {2} mid = 2L + R. If mid mid mid is a black spot, we will make the intermediate interval [mid, r] [mid, r] [r], otherwise, we will make the intermediate interval [l,mid][l,mid][l,mid].
- The above strategy can deal with cases where N < Log2109N < Log_210^9N < Log2 109.
- Two disjoint lines are selected for the above algorithm. Finally, a point in the middle interval is connected to get the desired line, so that the case of N < 2 Log2109N < 2 Log_210 9N < 2 Log2 109 can be handled.
- Time complexity O(N)O(N)O(N).
[Code]
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int main() { int n; read(n); int al = 0, ar = 1e9; int bl = 0, br = 1e9; for (int i = 1; i <= n; i++) { char s[15]; if (i & 1) { int mid = (al + ar) / 2; cout << 0 << ' ' << mid << endl; scanf("%s", s); if (s[0] == 'b') al = mid; else ar = mid; } else { int mid = (bl + br) / 2; cout << 1 << ' ' << mid << endl; scanf("%s", s); if (s[0] == 'b') bl = mid; else br = mid; } } cout << 0 << ' ' << (al + ar) / 2 << ' ' << 1 << ' ' << (bl + br) / 2 << endl; return 0; }
**[D]**Candies for Children
[Points of Thought]
- Set threshold alpha = O(K) alpha = O ( sqrt {K}) alpha = O(K).
- If N < alphaN < alphaN < alphaN < alpha, we can enumerate the number of candies used in a circle and simply judge its legitimacy.
- If N>alphaN>alphaN>alpha, we can enumerate the number of circles kkk. Let xxx be the number of 222 between [l,r][l,r][l,r], yyy be the number of 222, lenlenlenlenlenlenlenlenlenlenlen is the length of [l, r] [l, r], r]:
111 ,2(k+1)x+(k+1)(len−x)+2ky+k(N−len−y)=K2(k+1)x+(k+1)(len-x)+2ky+k(N-len-y)=K2(k+1)x+(k+1)(len−x)+2ky+k(N−len−y)=K
Where (x,y < N,x < [0,len],y < [0,N len]) (x,y in N,x in [0,len],y in [0,N-len]) (x,y < N,x < [0,len],y < [0,N len])
222 ,2(k+1)x+(k+1)(len−x)+2ky+k(N−len−y)=K−12(k+1)x+(k+1)(len-x)+2ky+k(N-len-y)=K-12(k+1)x+(k+1)(len−x)+2ky+k(N−len−y)=K−1
Where (x,y < N,x < [1,len],y < [0,N len]) (x,y in N,x in [1,len],y in [0,N-len]) (x,y < N,x < [1,len],y < [0,N len]) - Because we want to maximize x + y x + y x + y, take the maximum / minimum value of x x x, the maximum / minimum value of Y Y Y can be calculated separately.
- Time complexity O (K) O ( sqrt {K}) O (K).
[Code]
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } ll check(ll a, ll b, ll sum, ll x, ll la, ll ra, ll lb, ll rb) { ll y = sum - a * x; if (b != 0) assert(y % b == 0), y /= b; else assert(y == 0), y = rb; if (x >= la && x <= ra && y >= lb && y <= rb) return x + y; else return -1; } int main() { ll n, k, l, r, len; read(n), read(l), read(r), read(k); if (l <= r) len = r - l + 1; else len = n - l + 1 + r; if (n <= 1e7) { for (int i = n; i >= 0; i--) { ll tmp = k % (n + i); if (tmp == 0) tmp = n + i; if (tmp >= len && tmp >= 2 * len - (n - i + 1) && tmp <= 2 * len && tmp <= len + i) { writeln(i); return 0; } } printf("-1\n"); } else { ll ans = -1; for (int i = 0; i * n <= k; i++) { ll sum = k - (i + 1) * len - i * (n - len), tmp; if (i != 0) { tmp = sum % i; chkmax(ans, check(i + 1, i, sum, tmp, 0, len, 0, n - len)); chkmax(ans, check(i + 1, i, sum, tmp + (len - tmp) / i * i, 0, len, 0, n - len)); } tmp = (-sum % (i + 1) + (i + 1)) % (i + 1); chkmax(ans, check(i, i + 1, sum, tmp, 0, n - len, 0, len)); chkmax(ans, check(i, i + 1, sum, tmp + (n - len - tmp) / (i + 1) * (i + 1), 0, n - len, 0, len)); sum++; if (i != 0) { tmp = sum % i; chkmax(ans, check(i + 1, i, sum, tmp + (tmp != 0) * i, 1, len, 0, n - len)); chkmax(ans, check(i + 1, i, sum, tmp + (len - tmp) / i * i, 1, len, 0, n - len)); } tmp = (-sum % (i + 1) + (i + 1)) % (i + 1); chkmax(ans, check(i, i + 1, sum, tmp, 0, n - len, 1, len)); chkmax(ans, check(i, i + 1, sum, tmp + (n - len - tmp) / (i + 1) * (i + 1), 0, n - len, 1, len)); } writeln(ans); } return 0; }
**[E]**Lasers and Mirrors
[Points of Thought]
- First, if AI = ia_i = I AI = i, there is no need to put any mirror. The answer is NNN.
- Once any mirror is placed, the answer is at most N_1N-1N_1. We try to construct a set of solutions with the answer N_1N-1N_1.
- We might as well give up one beam of light xxx, so that we can use one line to guide another beam of light to the column where XXX is located. The number of rows used is N_1+c_1N-1+c-1N_1+c_1, where c c c denotes the number of permutation rings read in.
- Considering the optimal number of rows, the disadvantage of the above algorithm is that it costs an extra line to merge XXX into the permutation ring when dealing with each permutation ring that does not contain xxx. We give up light 111, so that whenever we want to merge 111 into the replacement ring, light 111 is in position 111, we can merge the operation of the replacement ring with the first exchange operation in one line. The number of rows used is reduced to N_1N-1N_1.
- Time complexity O(N2)O(N^2)O(N2).
[Code]
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e3 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int n, a[MAXN]; char ans[MAXN][MAXN]; int main() { read(n); bool all = true; for (int i = 1; i <= n; i++) { read(a[i]); if (a[i] != i) all = false; for (int j = 1; j <= n; j++) ans[i][j] = '.'; } if (all) { printf("%d\n", n); for (int i = 1; i <= n; i++) printf("%s\n", ans[i] + 1); return 0; } int token = 1, pos = 0; for (int i = 1; i <= n; i++) if (a[i] == 1) pos = i; for (int i = n; i >= 1; i--) { if (token == pos) { int dest = 0; for (int j = 1; j <= n; j++) if (a[j] < j) dest = j; if (dest == 0) continue; ans[i][dest] = ans[i][a[dest]] = ans[i][pos] = '\\'; int x = dest, y = a[dest]; swap(a[x], a[y]), swap(a[pos], a[x]), pos = x; } else { int dest = 0; for (int j = 1; j <= n; j++) if (a[j] == pos) dest = j; if (dest > pos) ans[i][dest] = ans[i][pos] = '\\'; else ans[i][dest] = ans[i][pos] = '/'; swap(a[pos], a[dest]), pos = dest; } } printf("%d\n", n - 1); for (int i = 1; i <= n; i++) printf("%s\n", ans[i] + 1); return 0; }
**[F]**String Journey
[Points of Thought]
- First of all, we may consider that the length of the selected iii substring from right to left is iii. Obviously, any scheme can be transformed into one that satisfies the above conditions.
- If we can choose x x x substrings backwards from iii, then we can choose x_1x-1x_1 substrings. Let dpidp_idpi denote the number of substrings that can be selected at most backward from iii, divide the DPDP value of each location directly, and use suffix array to judge whether it is feasible, time complexity O (NLog2N) O (NLog2N) O (NLog2N).
- Noting that DP i+1 (> DP i_1dp_{i+1} (> dp_i-1dp i+1 (> DP i_1), DP I (= DP i+1+1dp_i (= dp_{i+1}+1dp I (= DP i+1+1), we can judge the validity of each value by direct violence from large to small, and the total number of judgements is O(N)O(N). When judging, we can divide the lcplcplcp enough long interval on suffix array, and use segment tree to maintain the maximum value of the interval dpdp.
- Time complexity O(NLogN)O(NLogN)O(NLogN).
[Code]
#include<bits/stdc++.h> using namespace std; const int MAXN = 5e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct SegmentTree { struct Node { int lc, rc, Max; } a[MAXN * 2]; int n, size, root; void update(int root) { a[root].Max = max(a[a[root].lc].Max, a[a[root].rc].Max); } void build(int &root, int l, int r) { root = ++size; if (l == r) { a[root].Max = 0; return; } int mid = (l + r) / 2; build(a[root].lc, l, mid); build(a[root].rc, mid + 1, r); update(root); } void init(int x) { n = x; root = size = 0; build(root, 1, n); } void modify(int root, int l, int r, int pos, int d) { if (l == r) { a[root].Max = d; return; } int mid = (l + r) / 2; if (mid >= pos) modify(a[root].lc, l, mid, pos, d); else modify(a[root].rc, mid + 1, r, pos, d); update(root); } void modify(int pos, int d) { modify(root, 1, n, pos, d); } int query(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) return a[root].Max; int mid = (l + r) / 2, ans = 0; if (mid >= ql) chkmax(ans, query(a[root].lc, l, mid, ql, min(mid, qr))); if (mid + 1 <= qr) chkmax(ans, query(a[root].rc, mid + 1, r, max(mid + 1, ql), qr)); return ans; } int query(int l, int r) { if (l > r) return 0; else return query(root, 1, n, l, r); } } ST; namespace SuffixArray { const int MAXN = 5e5 + 5; const int MAXLOG = 22; const int MAXC = 256; int sa[MAXN], rnk[MAXN], height[MAXN]; int Min[MAXN][MAXLOG], bit[MAXN], N; void init(char *a, int n) { N = n; static int x[MAXN], y[MAXN], cnt[MAXN], rk[MAXN]; memset(cnt, 0, sizeof(cnt)); for (int i = 1; i <= n; i++) cnt[(int) a[i]]++; for (int i = 1; i <= MAXC; i++) cnt[i] += cnt[i - 1]; for (int i = n; i >= 1; i--) sa[cnt[(int) a[i]]--] = i; rnk[sa[1]] = 1; for (int i = 2; i <= n; i++) rnk[sa[i]] = rnk[sa[i - 1]] + (a[sa[i]] != a[sa[i - 1]]); for (int k = 1; rnk[sa[n]] != n; k <<= 1) { for (int i = 1; i <= n; i++) { x[i] = rnk[i]; y[i] = (i + k <= n) ? rnk[i + k] : 0; } memset(cnt, 0, sizeof(cnt)); for (int i = 1; i <= n; i++) cnt[y[i]]++; for (int i = 1; i <= n; i++) cnt[i] += cnt[i - 1]; for (int i = n; i >= 1; i--) rk[cnt[y[i]]--] = i; memset(cnt, 0, sizeof(cnt)); for (int i = 1; i <= n; i++) cnt[x[i]]++; for (int i = 1; i <= n; i++) cnt[i] += cnt[i - 1]; for (int i = n; i >= 1; i--) sa[cnt[x[rk[i]]]--] = rk[i]; rnk[sa[1]] = 1; for (int i = 2; i <= n; i++) rnk[sa[i]] = rnk[sa[i - 1]] + (x[sa[i]] != x[sa[i - 1]] || y[sa[i]] != y[sa[i - 1]]); } int now = 0; for (int i = 1; i <= n; i++) { if (now) now--; while (a[i + now] == a[sa[rnk[i] + 1] + now]) now++; height[rnk[i]] = now; } for (int i = 1; i <= n; i++) Min[i][0] = height[i]; for (int p = 1; p < MAXLOG; p++) { int tmp = 1 << (p - 1); for (int i = 1, j = tmp + 1; j <= n; i++, j++) Min[i][p] = min(Min[i][p - 1], Min[i + tmp][p - 1]); } for (int i = 1; i <= n; i++) { bit[i] = bit[i - 1]; if (i >= 1 << (bit[i] + 1)) bit[i]++; } } int lcp(int x, int y) { if (x == y) return N - sa[x] + 1; if (x > y) swap(x, y); int tmp = bit[y - x]; return min(Min[x][tmp], Min[y - (1 << tmp)][tmp]); } int dp[MAXN]; bool feasiable(int pos, int len) { if (len == 1) return true; len--; int l = 1, r = rnk[pos]; while (l < r) { int mid = (l + r) / 2; if (lcp(mid, rnk[pos]) >= len) r = mid; else l = mid + 1; } int ql = l; l = rnk[pos], r = N; while (l < r) { int mid = (l + r + 1) / 2; if (lcp(mid, rnk[pos]) >= len) l = mid; else r = mid - 1; } int qr = l; if (ST.query(ql, qr) >= len) return true; pos++; l = 1, r = rnk[pos]; while (l < r) { int mid = (l + r) / 2; if (lcp(mid, rnk[pos]) >= len) r = mid; else l = mid + 1; } ql = l; l = rnk[pos], r = N; while (l < r) { int mid = (l + r + 1) / 2; if (lcp(mid, rnk[pos]) >= len) l = mid; else r = mid - 1; } qr = l; return ST.query(ql, qr) >= len; } void work(int n) { int ans = 0, now = 1, pos = n + 1; for (int i = n; i >= 1; i--) { while (!feasiable(i, now)) { now--, pos--; ST.modify(rnk[pos], dp[pos]); } dp[i] = now; chkmax(ans, now); now = now + 1; } writeln(ans); } } int n; char s[MAXN]; int main() { read(n), ST.init(n); scanf("\n%s", s + 1); SuffixArray :: init(s, n); SuffixArray :: work(n); return 0; }