Op 1 is more difficult so try to relate Op 1 with Op 2. After Op 1
the number is still the same mod 11 and mod 3, so Op 1 is just doing Op
2 multiple times.
signedmain(){ ios::sync_with_stdio(false); cin.tie(0); int t; cin >> t; while (t--) solve(); }
B. Kevin and Permutation
Try to place a "1" that affect the most subarrays. This can be done
by placing "1" at position \(k\). Then
do this process recursively, that is, try to place a "2" that affect the
most subarrays. So "2" should be placed at position \(2k\). This process continues.
#include"bits/stdc++.h" #define int long long #define P pair<int,int> #define fi first #define se second usingnamespace std;
constint maxn = 1e5+5;
voidsolve(){ int n, k; cin >> n >> k; int R = n; int L = 1; for (int i=1;i<=n;i++) { if (i%k == 0) cout << L++ << " "; else cout << R-- << " "; } cout << endl; }
signedmain(){ ios::sync_with_stdio(false); cin.tie(0); int t; cin >> t; while (t--) solve(); }
C Kevin and Binary Strings
It's important to note that \(n \leq
5000\). Observe that the length of \(x\) and \(y\) should be long in \(x \oplus y\) to have the minimum number of
leading zeros. WLOG, should \(x\) just
be \(s\)? Well just let \(y\) to be the smallest possible string,
then clearly \(x \oplus y\) has the
same length as \(s\), and this cannot
be done by choosing any shorter \(x\)s,
so \(x = s\).
For \(y\), we just have to iterate
through all the possible substrings, but checking is quite hard and even
if possible will take time complexity like \(O(n^3)\). What I did is that I considered
\(t = s \oplus (2^{\inf}-1)\). We try
to find a substring of \(s\) that
matches the suffix of \(t\). When
clearly its not really possible but we can still match the first few
characters of the suffix of \(t\).
So I considered substrings of \(s\)
starting from a specific character. Up to a certain point, the answer
grows, then the answer decreases. We just have to find this changing
point, which is just the next different character. A bit more formally
find the next position in \(t\) such
that its different from the current character. The length of the
substring is the same as the length of the suffix of \(t\) from that point, and its optimal
because its the best match for \(t\).
#include"bits/stdc++.h" #define int long long #define P pair<int,int> #define fi first #define se second usingnamespace std;
vector<pair<string, P>> v;
voidsolve(){ v.clear(); string s; cin >> s; int n = s.size(); s = "#"+s; int p0 = -1; int p1 = -1; string sp = s; sp[1] = '0'; v.push_back({sp, {1, 1}}); for (int i=n;i>=1;i--) { if (s[i] == '0') { if (p1 == -1) { p0 = i; continue; } string t = s; for (int j=p1;j<=n;j++) { if (s[j] == s[j-p1+i]) t[j] = '0'; else t[j] = '1'; } v.push_back({t, {i, n-p1+i}}); p0 = i; } if (s[i] == '1') { if (p0 == -1) { p1 = i; continue; } string t = s; for (int j=p0;j<=n;j++) { if (s[j] == s[j-p0+i]) t[j] = '0'; else t[j] = '1'; } v.push_back({t, {i, n-p0+i}}); p1 = i; } } sort(v.begin(),v.end()); P ans = v.back().second; cout << 1 << " " << n << " " << ans.fi << " " << ans.se << endl; }
signedmain(){ ios::sync_with_stdio(false); cin.tie(0); int t; cin >> t; while (t--) solve(); }
D Kevin and Competition Memories
Start with small \(k\)s. I find out
that the \(b_i\) that is just larger
than Kevin is clearly the worst problem. Because almost everyone knows
how to solve except Kevin. More generally speaking, only the problem
that is just larger than Kevin's rating matters.
Consider the case where we give up no problems, that the worst
problem must be selected and contribute to the final answer. Now, since
in this problem set only the worst problem matters, just take the next
few worse problems.
Now let's go back to the case where we can give up problems, sort the
problems in ascending rating and give up the problems from the problem
that is just larger than Kevin's rating. Then group the problems in this
way: let say group size is \(k\). Sort
the problem in how bad the problem is (how many people knew to solve
except Kevin), if Kevin can solve, then = 0. Choose 1...k, k+1 .... 2k
and etc.
#include"bits/stdc++.h" #define int long long #define P pair<int,int> #define fi first #define se second usingnamespace std;
constint maxn = 3e5+5; int a[maxn]; int b[maxn]; int v[maxn]; int kevin; int n, m;
voidsolve(){ cin >> n >> m; for (int i=1;i<=n;i++) cin >> a[i]; for (int i=1;i<=m;i++) cin >> b[i]; kevin = a[1]; sort(a+1, a+n+1); sort(b+1, b+m+1); for (int i=1;i<=m;i++) { v[i] = lower_bound(a+1, a+n+1, b[i])-a-1; v[i] = n-v[i]; if (b[i] <= kevin) v[i] = 0; } dbg(v); int pos = upper_bound(b+1, b+m+1, kevin)-b; dbg(b[pos]); for (int k=1;k<=m;k++) { int ans = m/k; int x = m-m/k*k; for (int i=pos+x;i<=m;i+=k) { ans += v[i]; } cout << ans << " "; } cout << endl; }
signedmain(){ ios::sync_with_stdio(false); cin.tie(0); int t; cin >> t; while (t--) solve(); }
E Kevin and Bipartite Graph
Nothing much I can do except for guessing the answer. I guessed \(n \leq m\), but doesn't work. I guessed
\(2n \leq m\), but doesn't work because
\(n = 2\), \(m = 4\) is a counter example. So logically
try \(n = 2\) and \(m = 3\) and yes there is a solution by just
creating 2 zig zags.
1 2 3 4
Left side = 1,2,3,4 Right side = 1,2,3 Color 1: R1->12 R2->23 R3->34 Color 2: R1->34 R2->41 R3->12
Just follow this construction so basically:
1 2 3
Color 1: 12 23 34 45 56 ..... Color 2: 34 45 56 67 78 ..... Color 3: 45 56 67 78 89 .....
Clearly each color has no loops. This problem is really
confusing.
#include"bits/stdc++.h" #define int long long #define P pair<int,int> #define fi first #define se second usingnamespace std;
constint maxn = 2005; int E[maxn][maxn];
voidsolve(){ int n, m; cin >> n >> m; if (m >= n+n) { cout << "NO" << endl; } else { cout << "YES" << endl; for (int i=1;i<=m;i++) { int col = 0; for (int j=0;j<n+n;j+=2) { col++; int id1 = (i+j)%(n+n)+1; int id2 = (i+j+1)%(n+n)+1; E[id1][i] = col; E[id2][i] = col; } } for (int i=1;i<=n+n;i++) { for (int j=1;j<=m;j++) { cout << E[i][j] << " "; } cout << endl; } } }
signedmain(){ ios::sync_with_stdio(false); cin.tie(0); int t; cin >> t; while (t--) solve(); }
F Kevin and Math Class
This is quite a good problem. At first I tried to analyze array \(a\) but nothing worked. I just
observed that only the maximum value matter. Also, I
observed that the answer is at most \(70\). But not very useful. Then I tried to
analysis the ceiling function at its still doesn't work well because
even if I change the ceiling function to pure division I still can't
solve.
So the only thing left that I can do something on is \(b\) and I realized that quite lately. I
think there are some "optimal" ranges that are just better than some
other ranges. I can't really characterize this, but I think there are
only \(O(n)\) of them instead of \(O(n^2)\) which is easier to deal with. Then
I observe that the optimal ranges never intersect. This
reminded me of cartesian tree. Then the problem is just DP on the
cartesian tree.
Some important stuff to store during DP: maximum number in the range,
number of operation, and index. Well maximum number is \(1e18\) size so cannot be the index, and
recall that answer is at most \(70\),
now DP is natural.
Well I think this problem should be optimized to \((n\log n)\) by some sort of binary search
because the min-max convolution clearly only has \(O(n)\) meaningful operations. But I don't
really know how to implement so I kept optimizing and eventually made it
through will some interesting optimizations with two logs.
Luckily I forgot how to write cartesian tree but I remember segment
tree so I did that.
#include"bits/stdc++.h" #define int long long #define P pair<int,int> #define fi first #define se second usingnamespace std;
constint maxn = 2e5+5; constint maxc = 64; int a[maxn]; int b[maxn]; int n; int L[maxn]; int R[maxn];
intread(){ int x = 0; char c = getchar(); while (c<'0'||c>'9') { c = getchar(); } while (c>='0'&&c<='9') { x = x*10+c-'0'; c = getchar(); } return x; }
structnode { int l; int r; P v; }; node t[4*maxn];
voidbuild(int p, int l, int r){ t[p].l = l; t[p].r = r; if (l == r) { t[p].v = {b[l], l}; return; } int mid = (l+r)/2; build(p+p, l, mid); build(p+p+1, mid+1, r); pushup(p); }
P query(int p, int ql, int qr){ if (ql <= t[p].l && t[p].r <= qr) { return t[p].v; } int mid = (t[p].l+t[p].r)/2; P ans = {1e18, -1}; if (ql <= mid) ans = min(ans, query(p+p, ql, qr)); if (mid < qr) ans = min(ans, query(p+p+1, ql, qr)); return ans; }
voidcatesian(int l, int r){ int p = query(1, l, r).se; if (l <= p-1) { L[p] = query(1, l, p-1).se; catesian(l, p-1); } if (p+1 <= r) { R[p] = query(1, p+1, r).se; catesian(p+1, r); } }
int dp[maxn][maxc+1];
intc(int x, int y){ return x/y + (x%y != 0); }
voidDFS(int u){ if (L[u]) DFS(L[u]); if (R[u]) DFS(R[u]); for (int i=0;i<=maxc;i++) { dp[u][i] = 1e18; } for (int i=0;i<=maxc;i++) { for (int j=0;i+j<=maxc;j++) { dp[u][i+j] = min(dp[u][i+j], max({dp[L[u]][i], dp[R[u]][j], a[u]})); if (!dp[R[u]][j]) break; if (dp[R[u]][j] < dp[L[u]][i]) break; } if (!dp[L[u]][i]) break; } for (int i=1;i<=maxc;i++) { dp[u][i] = min(dp[u][i], c(dp[u][i-1], b[u])); } }
voidsolve(){ n = read(); for (int i=1;i<=n;i++) a[i] = read(); for (int i=1;i<=n;i++) { L[i] = R[i] = 0; b[i] = read(); } build(1, 1, n); catesian(1, n); int rt = query(1, 1, n).se; DFS(rt); for (int i=0;i<=maxc;i++) { if (dp[rt][i] == 1) { printf("%lld\n", i); return; } } }
signedmain(){ int t = read(); while (t--) solve(); }
G Kevin and Matrices
This problem is quite hard. I didn't make much progress initially so
I start with cases like 1xn, 2x2, 2xn, etc. For the 1xn case, it's
always true. For the 2xn case, let row 1 be \(a\) and row 2 be \(b\). Equation can be simplified to \(\min(\max a, \max b)\). WLOG, let \(\max a \leq \max b\).
Observe that RHS \(\leq \max
a\), because each column is compared against an element of \(a\) that is at most \(\max a\). So we eventually realize that LHS
\(\geq\) RHS. This can be extended to a
more general case. Key Observation: LHS = RHS.
Now lets fix \(A\), where A = LHS =
RHS, and fix the position of A (lets say there is only this single A
that satisfy the equation for simplicity). We have to put [1...A] in the
row and [A...v] in the column. The other vacant positions can be placed
arbitrarily.
Now consider the case with multiple \(A\)s that is row maximum and col minimum
(lets call this kind of \(A\) a key
\(A\)). Draw out these rows and cols,
and observe that the intersection of these rows and
cols are also key \(A\)s. Basically the
key \(A\)s form a submatrix. Now we can
see that this is similar to inclusion-exclusion, where we can easily
find things \(\geq\) something and its
crucial to remove repeats.
So fix \(r\), rows for this
sub-matrix, and fix \(c\), cols, and
fix \(A\). Do some math and apply
in-ex. The issue is that the in-ex coefficient is hard to decide. \((-1)^{rc}\) doesn't make sense because for
example in the 2x2 case matrix (2,2)(2,2) is {1x1}4-{1x2}4+{2x2}1,
coefficient for {2x2} is 1. So I guessed its \((-1)^{r+c}\).
I thought of it for a while and don't understand why it works. Now I
think its just doing two in-ex separately on two dimensions, resulting a
factor of \((-1)^{r+1}(-1)^{c+1}\),
which is in the desired form.