【比赛链接】
**【ANDSQR】**AND Square Subsegments
【思路要点】
- 离线询问,按左端点排序。
- 枚举区间的左端点 l l l ,区间 [ l , i ] [l,i] [l,i] 的 a n d and and 和至多变化 O ( L o g V ) O(LogV) O(LogV) 次,二分找到分界点,并找到其中是完全平方数的。
- 每一段 a n d and and 和相同的区间 [ l , i ] [l,i] [l,i] 对答案的贡献可以用一个关于右端点位置的一次函数来描述,用线段树模拟即可。
- 单组数据时间复杂度 O ( Q L o g N + N L o g N L o g V ) O(QLogN+NLogNLogV) O(QLogN+NLogNLogV) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const int MAXQ = 5e5 + 5; const int MAXLOG = 20; 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, self; long long add; } a[MAXN * 2]; int n, q, root, size; vector <int> home[MAXN]; long long ans[MAXQ]; int newnode() { size++; a[size].lc = a[size].rc = 0; a[size].add = a[size].self = 0; return size; } void build(int &root, int l, int r) { root = newnode(); if (l == r) return; int mid = (l + r) / 2; build(a[root].lc, l, mid); build(a[root].rc, mid + 1, r); } void init(int x, int y) { n = x, q = y; root = size = 0; build(root, 1, n); for (int i = 1; i <= n; i++) home[i].clear(); for (int i = 1; i <= q; i++) ans[i] = 0; } void pushdown(int root) { a[a[root].lc].add += a[root].add; a[a[root].rc].add += a[root].add; a[a[root].lc].self += a[root].self; a[a[root].rc].self += a[root].self; a[root].add = a[root].self = 0; } void addquery(int root, int l, int r, int pos, int from) { if (l == r) { home[pos].push_back(from); ans[from] -= a[root].add + 1ll * a[root].self * pos; return; } pushdown(root); int mid = (l + r) / 2; if (mid >= pos) addquery(a[root].lc, l, mid, pos, from); else addquery(a[root].rc, mid + 1, r, pos, from); } void addquery(int pos, int from) { addquery(root, 1, n, pos, from); } void add(int root, int l, int r, int ql, int qr, int val) { if (l == ql && r == qr) { a[root].add += val; return; } int mid = (l + r) / 2; if (mid >= ql) add(a[root].lc, l, mid, ql, min(mid, qr), val); if (mid + 1 <= qr) add(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, val); } void mns(int root, int l, int r, int ql, int qr, int val) { if (l == ql && r == qr) { a[root].add -= val; a[root].self++; return; } int mid = (l + r) / 2; if (mid >= ql) mns(a[root].lc, l, mid, ql, min(mid, qr), val); if (mid + 1 <= qr) mns(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, val); } void addvalue(int lft, int l, int r) { int len = r - l + 1; if (r + 1 <= n) add(root, 1, n, r + 1, n, len); mns(root, 1, n, l, r, l - 1); } void dfs(int root, int l, int r) { if (l == r) { for (unsigned i = 0; i < home[l].size(); i++) ans[home[l][i]] += a[root].add + 1ll * a[root].self * l; return; } pushdown(root); int mid = (l + r) / 2; dfs(a[root].lc, l, mid); dfs(a[root].rc, mid + 1, r); } void output() { dfs(root, 1, n); for (int i = 1; i <= q; i++) writeln(ans[i]); } } ST; int Log[MAXN], val[MAXN][MAXLOG]; vector <int> rp[MAXN], home[MAXN]; int query(int l, int r) { int tmp = Log[r - l + 1]; return val[l][tmp] & val[r - (1 << tmp) + 1][tmp]; } bool square(int x) { int tmp = sqrt(x) + 1e-8; return tmp * tmp == x; } int main() { int T; read(T); while (T--) { int n, q; read(n), read(q); ST.init(n, q); for (int i = 1; i <= n; i++) { read(val[i][0]); rp[i].clear(); home[i].clear(); Log[i] = Log[i - 1]; if ((1 << (Log[i] + 1)) == i) Log[i]++; } for (int p = 1; p < MAXLOG; p++) for (int i = 1, j = 1 + (1 << (p - 1)); j <= n; i++, j++) val[i][p] = val[i][p - 1] & val[j][p - 1]; for (int i = 1; i <= q; i++) { int x, y; read(x), read(y); rp[x].push_back(y); home[x].push_back(i); } for (int i = 1; i <= n; i++) { for (unsigned j = 0; j < rp[i].size(); j++) ST.addquery(rp[i][j], home[i][j]); for (int j = i, nxt; j <= n; j = nxt) { int l = j, r = n, now = query(i, j); while (l < r) { int mid = (l + r + 1) / 2; if (query(i, mid) == now) l = mid; else r = mid - 1; } if (square(now)) ST.addvalue(i, j, l); nxt = l + 1; } } ST.output(); } return 0; }
**【BSHUFFLE】**Bad Shuffle
【思路要点】
- 似乎有这么个结论,令 M = ⌊ N 2 ⌋ M=\lfloor \frac{N}{2}\rfloor M=⌊2N⌋ 。
- 那么有
P 1 = ( M , 1 , 2 , . . . , M − 1 , N , M + 1 , M + 2 , . . . , N − 1 ) P_1=(M,1,2,...,M-1,N,M+1,M+2,...,N-1) P1=(M,1,2,...,M−1,N,M+1,M+2,...,N−1)
P 2 = ( N , 1 , 2 , 3 , . . . , N − 1 ) P_2=(N,1,2,3,...,N-1) P2=(N,1,2,3,...,N−1)- 证明可见 题解里提到的一篇论文 。
- 或者一个普通人可以通过打表找到答案的规律。
- 本结论也可以在 Oeis 找到。
- 时间复杂度 O ( N ) O(N) O(N) 。
【代码】
#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(""); } void print(int start, int cnt) { if (cnt == 0) return; for (int i = 1; i <= cnt - 1; i++) printf("%d ", start + i); printf("%d ", start); } int main() { int n; read(n); int m = n / 2; print(1, m); print(m + 1, n - m); printf("\n"); printf("%d ", n); for (int i = 1; i <= n - 1; i++) printf("%d ", i); printf("\n"); return 0; }
**【CHEFADV】**Chef and Adventures
【思路要点】
- 枚举是否进行操作 3 3 3 ,判断模数是否为零。
- 单组数据时间复杂度 O ( 1 ) O(1) O(1) 。
【代码】
#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 T; read(T); while (T--) { ll n, m, a, b; read(n), read(m); read(a), read(b); n--, m--; if (n % a == 0 && m % b == 0) printf("Chefirnemo\n"); else if (n >= 1 && m >= 1 && (n - 1) % a == 0 && (m - 1) % b == 0) printf("Chefirnemo\n"); else printf("Pofik\n"); } return 0; }
**【CHEFLST】**Chef and Lost Story
【思路要点】
- 将矩阵中的每一个元素看做集合幂级数,我们需要判断乘法定义为异或卷积的情况下矩阵积和式的每一项系数是否为 0 0 0 。
- 积和式较为难求,我们将集合幂级数的每一项乘上一个随机系数,求行列式。
- 即将矩阵中的每一个集合幂级数 F W T FWT FWT ,求矩阵每一位的行列式,再 U F W T UFWT UFWT 回去。
- 单组数据时间复杂度 O ( N 3 ∗ V + N 2 ∗ V L o g V ) O(N^3*V+N^2*VLogV) O(N3∗V+N2∗VLogV) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 65; const int MAXM = 1024; const int P = 1e9 + 7; const int inv2 = (P + 1) / 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(""); } unsigned seed; int n, res[MAXM], a[MAXN][MAXN][MAXM], b[MAXN][MAXN]; unsigned Rand() { seed = seed * seed + rand(); return seed; } int power(int x, int y) { if (y == 0) return 1; int tmp = power(x, y / 2); if (y % 2 == 0) return 1ll * tmp * tmp % P; else return 1ll * tmp * tmp % P * x % P; } int gauss() { int f = 1, ans = 1; for (int i = 1; i <= n; i++) { for (int j = i; j <= n; j++) if (b[j][i] != 0) { swap(b[i], b[j]); if (i != j) f = P - f; } if (b[i][i] == 0) return 0; ans = 1ll * ans * b[i][i] % P; int inv = power(b[i][i], P - 2); for (int j = i + 1; j <= n; j++) { int tmp = 1ll * b[j][i] * inv % P; for (int k = i; k <= n; k++) b[j][k] = (b[j][k] - 1ll * b[i][k] * tmp % P + P) % P; } } return 1ll * ans * f % P; } void FWT(int *a, int N) { for (int len = 2; len <= N; len <<= 1) for (int i = 0; i < N; i += len) for (int j = i, k = i + len / 2; k < i + len; j++, k++) { int tmp = (a[j] + a[k]) % P, tnp = (a[j] - a[k] + P) % P; a[j] = tmp, a[k] = tnp; } } void UFWT(int *a, int N) { for (int len = 2; len <= N; len <<= 1) for (int i = 0; i < N; i += len) for (int j = i, k = i + len / 2; k < i + len; j++, k++) { int tmp = (a[j] + a[k]) % P, tnp = (a[j] - a[k] + P) % P; a[j] = 1ll * tmp * inv2 % P, a[k] = 1ll * tnp * inv2 % P; } } int main() { int T; read(T); while (T--) { read(n); int Max = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { read(b[i][j]); chkmax(Max, b[i][j]); } int N = 1; while (N <= Max) N <<= 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { memset(a[i][j], 0, sizeof(a[i][j])); a[i][j][b[i][j]] = Rand() % P; FWT(a[i][j], N); } for (int val = 0; val <= N - 1; val++) { for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) b[i][j] = a[i][j][val]; res[val] = gauss(); } UFWT(res, N); for (int i = 0; i <= N - 1; i++) if (res[i]) printf("%d ", i); printf("\n"); } return 0; }
**【CHEFZERO】**Chef and Condition Zero
【思路要点】
- 笔者的做法是将矩阵看做一维,然后贪心分段,再在这个解的基础上进行微调。
- 可以得到不错的效果。
- 时间复杂度 O ( N M ) O(NM) O(NM) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e3 + 5; const int MAXM = 1e6 + 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 point {int x, y; }; int n, m, k, a[MAXN][MAXN]; int l[MAXN], r[MAXN]; int ans[MAXN][MAXN]; int finalans[MAXN][MAXN]; long long now[MAXN]; long long sum[MAXM]; point pos[MAXM]; long long get1(int cnt) { int tot = 0; memset(now, 0, sizeof(now)); for (int i = 1; i <= n; i++) { if (i & 1) { for (int j = 1; j <= m; j++) pos[++tot] = (point) {i, j}; } else { for (int j = m; j >= 1; j--) pos[++tot] = (point) {i, j}; } } for (int i = 1; i <= tot; i++) sum[i] = sum[i - 1] + a[pos[i].x][pos[i].y]; int lft = tot; for (int i = k; i >= 1; i--) { long long goal = sum[lft] / i; r[i] = lft; while (abs(now[i] - goal) > abs(now[i] + a[pos[lft].x][pos[lft].y] - goal)) { now[i] += a[pos[lft].x][pos[lft].y]; lft--; } l[i] = lft + 1; } while (cnt--) { if (cnt & 1) { for (int i = 1; i <= k - 1; i++) { if (abs(now[i] + 2 * a[pos[l[i + 1]].x][pos[l[i + 1]].y] - now[i + 1]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[l[i + 1]].x][pos[l[i + 1]].y]; l[i + 1]++, r[i]++; now[i] += tmp; now[i + 1] -= tmp; } if (abs(now[i + 1] + 2 * a[pos[r[i]].x][pos[r[i]].y] - now[i]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[r[i]].x][pos[r[i]].y]; l[i + 1]--, r[i]--; now[i] -= tmp; now[i + 1] += tmp; } } } else { for (int i = k - 1; i >= 1; i--) { if (abs(now[i] + 2 * a[pos[l[i + 1]].x][pos[l[i + 1]].y] - now[i + 1]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[l[i + 1]].x][pos[l[i + 1]].y]; l[i + 1]++, r[i]++; now[i] += tmp; now[i + 1] -= tmp; } if (abs(now[i + 1] + 2 * a[pos[r[i]].x][pos[r[i]].y] - now[i]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[r[i]].x][pos[r[i]].y]; l[i + 1]--, r[i]--; now[i] -= tmp; now[i + 1] += tmp; } } } } for (int i = 1; i <= k; i++) for (int j = l[i]; j <= r[i]; j++) ans[pos[j].x][pos[j].y] = i; sort(now + 1, now + k + 1); return now[k] - now[1]; } long long get2(int cnt) { int tot = 0; memset(now, 0, sizeof(now)); for (int i = 1; i <= n; i++) { if ((i & 1) == 0) { for (int j = 1; j <= m; j++) pos[++tot] = (point) {i, j}; } else { for (int j = m; j >= 1; j--) pos[++tot] = (point) {i, j}; } } for (int i = 1; i <= tot; i++) sum[i] = sum[i - 1] + a[pos[i].x][pos[i].y]; int lft = tot; for (int i = k; i >= 1; i--) { long long goal = sum[lft] / i; r[i] = lft; while (abs(now[i] - goal) > abs(now[i] + a[pos[lft].x][pos[lft].y] - goal)) { now[i] += a[pos[lft].x][pos[lft].y]; lft--; } l[i] = lft + 1; } while (cnt--) { if (cnt & 1) { for (int i = 1; i <= k - 1; i++) { if (abs(now[i] + 2 * a[pos[l[i + 1]].x][pos[l[i + 1]].y] - now[i + 1]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[l[i + 1]].x][pos[l[i + 1]].y]; l[i + 1]++, r[i]++; now[i] += tmp; now[i + 1] -= tmp; } if (abs(now[i + 1] + 2 * a[pos[r[i]].x][pos[r[i]].y] - now[i]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[r[i]].x][pos[r[i]].y]; l[i + 1]--, r[i]--; now[i] -= tmp; now[i + 1] += tmp; } } } else { for (int i = k - 1; i >= 1; i--) { if (abs(now[i] + 2 * a[pos[l[i + 1]].x][pos[l[i + 1]].y] - now[i + 1]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[l[i + 1]].x][pos[l[i + 1]].y]; l[i + 1]++, r[i]++; now[i] += tmp; now[i + 1] -= tmp; } if (abs(now[i + 1] + 2 * a[pos[r[i]].x][pos[r[i]].y] - now[i]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[r[i]].x][pos[r[i]].y]; l[i + 1]--, r[i]--; now[i] -= tmp; now[i + 1] += tmp; } } } } for (int i = 1; i <= k; i++) for (int j = l[i]; j <= r[i]; j++) ans[pos[j].x][pos[j].y] = i; sort(now + 1, now + k + 1); return now[k] - now[1]; } long long get3(int cnt) { int tot = 0; memset(now, 0, sizeof(now)); for (int j = 1; j <= m; j++) { if (j & 1) { for (int i = 1; i <= n; i++) pos[++tot] = (point) {i, j}; } else { for (int i = n; i >= 1; i--) pos[++tot] = (point) {i, j}; } } for (int i = 1; i <= tot; i++) sum[i] = sum[i - 1] + a[pos[i].x][pos[i].y]; int lft = tot; for (int i = k; i >= 1; i--) { long long goal = sum[lft] / i; r[i] = lft; while (abs(now[i] - goal) > abs(now[i] + a[pos[lft].x][pos[lft].y] - goal)) { now[i] += a[pos[lft].x][pos[lft].y]; lft--; } l[i] = lft + 1; } while (cnt--) { if (cnt & 1) { for (int i = 1; i <= k - 1; i++) { if (abs(now[i] + 2 * a[pos[l[i + 1]].x][pos[l[i + 1]].y] - now[i + 1]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[l[i + 1]].x][pos[l[i + 1]].y]; l[i + 1]++, r[i]++; now[i] += tmp; now[i + 1] -= tmp; } if (abs(now[i + 1] + 2 * a[pos[r[i]].x][pos[r[i]].y] - now[i]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[r[i]].x][pos[r[i]].y]; l[i + 1]--, r[i]--; now[i] -= tmp; now[i + 1] += tmp; } } } else { for (int i = k - 1; i >= 1; i--) { if (abs(now[i] + 2 * a[pos[l[i + 1]].x][pos[l[i + 1]].y] - now[i + 1]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[l[i + 1]].x][pos[l[i + 1]].y]; l[i + 1]++, r[i]++; now[i] += tmp; now[i + 1] -= tmp; } if (abs(now[i + 1] + 2 * a[pos[r[i]].x][pos[r[i]].y] - now[i]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[r[i]].x][pos[r[i]].y]; l[i + 1]--, r[i]--; now[i] -= tmp; now[i + 1] += tmp; } } } } for (int i = 1; i <= k; i++) for (int j = l[i]; j <= r[i]; j++) ans[pos[j].x][pos[j].y] = i; sort(now + 1, now + k + 1); return now[k] - now[1]; } long long get4(int cnt) { int tot = 0; memset(now, 0, sizeof(now)); for (int j = 1; j <= m; j++) { if ((j & 1) == 0) { for (int i = 1; i <= n; i++) pos[++tot] = (point) {i, j}; } else { for (int i = n; i >= 1; i--) pos[++tot] = (point) {i, j}; } } for (int i = 1; i <= tot; i++) sum[i] = sum[i - 1] + a[pos[i].x][pos[i].y]; int lft = tot; for (int i = k; i >= 1; i--) { long long goal = sum[lft] / i; r[i] = lft; while (abs(now[i] - goal) > abs(now[i] + a[pos[lft].x][pos[lft].y] - goal)) { now[i] += a[pos[lft].x][pos[lft].y]; lft--; } l[i] = lft + 1; } while (cnt--) { if (cnt & 1) { for (int i = 1; i <= k - 1; i++) { if (abs(now[i] + 2 * a[pos[l[i + 1]].x][pos[l[i + 1]].y] - now[i + 1]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[l[i + 1]].x][pos[l[i + 1]].y]; l[i + 1]++, r[i]++; now[i] += tmp; now[i + 1] -= tmp; } if (abs(now[i + 1] + 2 * a[pos[r[i]].x][pos[r[i]].y] - now[i]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[r[i]].x][pos[r[i]].y]; l[i + 1]--, r[i]--; now[i] -= tmp; now[i + 1] += tmp; } } } else { for (int i = k - 1; i >= 1; i--) { if (abs(now[i] + 2 * a[pos[l[i + 1]].x][pos[l[i + 1]].y] - now[i + 1]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[l[i + 1]].x][pos[l[i + 1]].y]; l[i + 1]++, r[i]++; now[i] += tmp; now[i + 1] -= tmp; } if (abs(now[i + 1] + 2 * a[pos[r[i]].x][pos[r[i]].y] - now[i]) < abs(now[i] - now[i + 1])) { int tmp = a[pos[r[i]].x][pos[r[i]].y]; l[i + 1]--, r[i]--; now[i] -= tmp; now[i + 1] += tmp; } } } } for (int i = 1; i <= k; i++) for (int j = l[i]; j <= r[i]; j++) ans[pos[j].x][pos[j].y] = i; sort(now + 1, now + k + 1); return now[k] - now[1]; } int main() { read(n), read(m), read(k); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) read(a[i][j]); long long Min = 1e18, tmp; tmp = get1(1000); //cerr << tmp << endl; if (tmp < Min) { Min = tmp; memcpy(finalans, ans, sizeof(ans)); } tmp = get2(1000); //cerr << tmp << endl; if (tmp < Min) { Min = tmp; memcpy(finalans, ans, sizeof(ans)); } tmp = get3(1000); //cerr << tmp << endl; if (tmp < Min) { Min = tmp; memcpy(finalans, ans, sizeof(ans)); } tmp = get4(1000); //cerr << tmp << endl; if (tmp < Min) { Min = tmp; memcpy(finalans, ans, sizeof(ans)); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) printf("%d ", finalans[i][j]); printf("\n"); } return 0; }
**【FCTR】**Factorize
【思路要点】
- 一个类似于 M i l l e r − R a b b i n Miller-Rabbin Miller−Rabbin 的分解质因数方式,但我不想写高精度。
- 官方题解 。
【代码】
No code yet.
**【MAGICHF】**Magician versus Chef
【思路要点】
- 按照题意模拟。
- 单组数据时间复杂度 O ( S ) O(S) O(S) 。
【代码】
#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 T; read(T); while (T--) { int n, ans, s; read(n), read(ans), read(s); while (s--) { int x, y; read(x), read(y); if (x == ans) ans = y; else if (y == ans) ans = x; } writeln(ans); } return 0; }
**【PHOTOCOM】**Sasha and Photos
【思路要点】
- 首先,有一个简单的单组数据时间复杂度 O ( M a x { h 1 , h 2 } ∗ M a x { w 1 , w 2 } ) O(Max\{h_1,h_2\}*Max\{w_1,w_2\}) O(Max{h1,h2}∗Max{w1,w2}) 的暴力,即将相同的行列一起考虑。
- 在内层用前缀和优化该暴力即可。
- 单组数据时间复杂度 O ( M a x { h 1 , h 2 } ∗ M i n { w 1 , w 2 } ) O(Max\{h_1,h_2\}*Min\{w_1,w_2\}) O(Max{h1,h2}∗Min{w1,w2}) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e6 + 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(""); } long long ans; int n1, m1, n2, m2, sum[2][MAXN]; char s[MAXN], t[MAXN]; int gcd(int x, int y) { if (y == 0) return x; else return gcd(y, x % y); } void recalsum(char *t) { for (int i = 1; i <= m2; i++) { sum[0][i] = sum[0][i - 1] + (t[i] == '0'); sum[1][i] = sum[1][i - 1] + (t[i] == '1'); } } long long Count(int t, long long pos, char *s) { int q = pos / m1, r = pos % m1; return 1ll * sum[t][q] * m1 + 1ll * r * (s[q + 1] == '0' + t); } long long calc(char *s, char *t) { long long ans = 0; for (int i = 1; i <= m1; i++) { long long l = (i - 1ll) * m2, r = l + m2; if (s[i] == '1') ans += Count(1, r, t) - Count(1, l, t); else ans += Count(0, r, t) - Count(0, l, t); } return ans; } int main() { int T; read(T); while (T--) { read(n1), read(m1); scanf("\n%s", s + 1); read(n2), read(m2); scanf("\n%s", t + 1); if (m1 > m2) { swap(s, t); swap(n1, n2); swap(m1, m2); } int i1 = 1, i2 = 1, lft1 = n2, lft2 = n1; ans = 0, recalsum(t); while (i1 <= n1 && i2 <= n2) { int used = min(lft1, lft2); ans += used * calc(s + (i1 - 1) * m1, t + (i2 - 1) * m2); lft1 -= used, lft2 -= used; if (lft1 == 0) i1++, lft1 = n2; if (lft2 == 0) { i2++, lft2 = n1; recalsum(t + (i2 - 1) * m2); } } writeln(ans / gcd(n1, n2) / gcd(m1, m2)); } return 0; }
**【STCFOTT】**Selinas the Chefs Falling on the Tree
【思路要点】
- 注意到两个相撞的单位会向原本的方向跑去,与没有相撞时实际上没有本质区别。因此我们不妨去除单位相撞的限制。
- 剩余的问题就是一个简单的期望 D P DP DP 了。
- 时间复杂度 O ( M L o g M + N Q ) O(MLogM+NQ) O(MLogM+NQ) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 255; const int P = 998244353; 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(""); } vector <int> a[MAXN], b[MAXN]; int n, father[MAXN], inv[MAXN]; int m, q, t[MAXN], ans[MAXN]; int p[2][3][MAXN]; int power(int x, int y) { if (y == 0) return 1; int tmp = power(x, y / 2); if (y % 2 == 0) return 1ll * tmp * tmp % P; else return 1ll * tmp * tmp % P * x % P; } void work(int pos, int fa) { father[pos] = fa; for (unsigned i = 0; i < a[pos].size(); i++) if (a[pos][i] != fa) { b[pos].push_back(a[pos][i]); work(a[pos][i], pos); } inv[pos] = power(b[pos].size(), P - 2); } void update(int &x, int y) { x += y; if (x >= P) x -= P; } int main() { read(n); for (int i = 1; i <= n - 1; i++) { int x, y; read(x), read(y); a[x].push_back(y); a[y].push_back(x); } work(1, 0); read(m); for (int i = 1; i <= m; i++) read(t[i]); read(q); sort(t + 1, t + m + 1); for (int i = 1; i <= m; i++) t[i] = q - t[i]; while (m >= 1 && t[m] < 0) m--; p[0][0][1] = 1, p[0][2][1] = 1; for (int i = 0, now = 0, dest = 1; m >= 1; i++, swap(now, dest)) { while (m >= 1 && t[m] == i) { m--; for (int j = 1; j <= n; j++) update(ans[j], p[now][2][j]); } memset(p[dest], 0, sizeof(p[dest])); memcpy(p[dest][2], p[now][2], sizeof(p[now][2])); for (int j = 1; j <= n; j++) { if (inv[j] == 0) { update(p[dest][1][father[j]], p[now][0][j]); update(p[dest][2][father[j]], p[now][0][j]); } else { int tmp = 1ll * p[now][0][j] * inv[j] % P; for (unsigned k = 0; k < b[j].size(); k++) { update(p[dest][0][b[j][k]], tmp); update(p[dest][2][b[j][k]], tmp); } } if (j != 1) { update(p[dest][1][father[j]], p[now][1][j]); update(p[dest][2][father[j]], p[now][1][j]); } else { int tmp = 1ll * p[now][1][j] * inv[j] % P; for (unsigned k = 0; k < b[j].size(); k++) { update(p[dest][0][b[j][k]], tmp); update(p[dest][2][b[j][k]], tmp); } } } } for (int i = 1; i <= n; i++) printf("%d ", ans[i]); return 0; }
**【TABGAME】**Table Game
【思路要点】
- D P DP DP 算出最靠近边缘的 2 2 2 行/列的胜负性。
- 剩余位置 ( i , j ) (i,j) (i,j) 的胜负性等同于 ( i − 1 , j − 1 ) (i-1,j-1) (i−1,j−1) 的胜负性。
- 单组数据时间复杂度 O ( N + M + Q ) O(N+M+Q) O(N+M+Q) 。
【代码】
#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], t[MAXN]; bool ans[3][MAXN], bns[MAXN][3]; int main() { int T; read(T); while (T--) { scanf("\n%s", t + 1); scanf("\n%s", s + 1); int n = strlen(s + 1), m = strlen(t + 1); chkmax(n, 2), chkmax(m, 2); for (int i = 1; i <= n; i++) { if (i <= 2) ans[i][0] = s[i] == '1'; bns[i][0] = s[i] == '1'; } for (int i = 1; i <= m; i++) { if (i <= 2) bns[0][i] = t[i] == '1'; ans[0][i] = t[i] == '1'; } for (int i = 1; i <= 2; i++) for (int j = 1; j <= m; j++) ans[i][j] = !ans[i - 1][j] || !ans[i][j - 1]; for (int i = 1; i <= n; i++) for (int j = 1; j <= 2; j++) bns[i][j] = !bns[i - 1][j] || !bns[i][j - 1]; int q; read(q); for (int i = 1; i <= q; i++) { int x, y; read(x), read(y); if (x <= 2) printf("%d", ans[x][y]); else if (y <= 2) printf("%d", bns[x][y]); else if (x <= y) printf("%d", ans[2][y - x + 2]); else printf("%d", bns[x - y + 2][2]); } printf("\n"); } return 0; }
**【XORIER】**War of XORs
【思路要点】
- 计算异或和是不小于 4 4 4 的偶数的数的对数。
- 单组数据时间复杂度 O ( N + A i ) O(N+A_i) O(N+Ai) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const int MAXV = 1e6 + 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 a[MAXN], cnt[MAXV]; int main() { int T; read(T); while (T--) { int n; read(n); int odd = 0, even = 0; memset(cnt, 0, sizeof(cnt)); for (int i = 1; i <= n; i++) { read(a[i]); cnt[a[i]]++; if (a[i] & 1) odd++; else even++; } long long ans = 1ll * odd * odd + 1ll * even * even; for (int i = 1; i <= 1e6; i++) { ans -= 1ll * cnt[i] * cnt[i]; ans -= 1ll * cnt[i] * cnt[i ^ 2]; } writeln(ans / 2); } return 0; }