版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/82973997
【比赛链接】
**【BBRICKS】**Beautiful Bricks
【思路要点】
- 上下两个砖块中,至多有一个黑色。
- 连续的一段存在黑色的行共有两种放置的方案。
- 枚举有几段连续的存在黑色的行,用组合数计算答案。
- 单组数据时间复杂度 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const int P = 1e9 + 7; 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, k, bit[MAXN], fac[MAXN], inv[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; } int getc(int x, int y) { if (y > x) return 0; else return 1ll * fac[x] * inv[y] % P * inv[x - y] % P; } int main() { k = 1e3; fac[0] = 1; for (int i = 1; i <= k; i++) fac[i] = 1ll * fac[i - 1] * i % P; inv[k] = power(fac[k], P - 2); for (int i = k - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1ll) % P; bit[0] = 1; for (int i = 1; i <= k; i++) bit[i] = bit[i - 1] * 2 % P; int T; read(T); while (T--) { read(n), read(k); int tmp = n - k + 1; int ans = 0, now = 1; if (tmp < 0) now = 0; for (int i = 1; i <= k; i++) { now = 1ll * now * (tmp - i + 1) % P; ans = (ans + 1ll * getc(k - 1, i - 1) * now % P * inv[i] % P * bit[i]) % P; } writeln(ans); } return 0; }
**【BITOBYT】**Byte to Bit
【思路要点】
- 每个时刻只可能存在一种角色,每 个时间单位数量翻倍。
- 直接计算答案即可。
- 时间复杂度 。
【代码】
#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 power(int x, int y) { if (y == 0) return 1; ll tmp = power(x, y / 2); if (y % 2 == 0) return tmp * tmp; else return tmp * tmp * x; } int main() { int T; read(T); while (T--) { int n; read(n); int q = n / 26, r = n % 26; if (r == 0) q--, r = 26; ll x = 0, y = 0, z = 0, ans = power(2, q); if (r <= 2) x = ans; else if (r <= 10) y = ans; else z = ans; printf("%lld %lld %lld\n", x, y, z); } return 0; }
**【CCIRCLES】**Chef and Circles
【思路要点】
- 枚举一对圆,能够达到的距离是一个区间,算出该区间即可。
- 注意圆相互包含和外离的情况。
- 时间复杂度 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e3 + 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 n, q, r[MAXN], ans[MAXV]; struct point {int x, y; } a[MAXN]; point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; } long long dist(point a) {return 1ll * a.x * a.x + 1ll * a.y * a.y; } int main() { read(n), read(q); for (int i = 1; i <= n; i++) read(a[i].x), read(a[i].y), read(r[i]); for (int i = 1; i <= n; i++) for (int j = i + 1; j <= n; j++) { ll tmp = dist(a[i] - a[j]); int Max = sqrt(tmp); int Min = sqrt(tmp); if (1ll * Min * Min < tmp) Min++; if (Min - r[i] - r[j] >= 0) Min = Min - r[i] - r[j]; else Min = max(0, abs(r[i] - r[j]) - Max); Max = min(1000000, Max + r[i] + r[j]); ans[Min]++, ans[Max + 1]--; } for (int i = 1; i < MAXV; i++) ans[i] += ans[i - 1]; while (q--) { int x; read(x); printf("%d\n", ans[x]); } return 0; }
**【CHSERVE】**Chef and Serves
【思路要点】
- 直接计算答案就好。
- 时间复杂度 。
【代码】
#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 x, y, k; read(x), read(y), read(k); int tmp = (x + y + 1) % (2 * k); if (tmp == 0) tmp = 2 * k; if (tmp <= k) printf("CHEF\n"); else printf("COOK\n"); } return 0; }
**【CPCOMP】**Coprime Components
【思路要点】
- 首先显然所有形如 的数等价于 ,不妨先做这一步转化。
- 有一种较为简单的 的做法,用 记录每一个质数作为质因数出现的位置,对于一个数 将其所有质因数的 或起来再取反,就可以得到它的边集,简单搜索即可。
- 但这样的做法复杂度太高,注意到 的质因数每个数只有一个,考虑将所有数按照最大的质因数分组。若 最大的质因数 ,那么 会连向不是同组、且与 互质的数,通过一些细节处理可以在 的时间复杂度内进行等价的连边。
- 剩余的不存在 的质因数的数的个数不超过 。
- 时间复杂度 ,其中 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const int P = 100; const int Q = 3e4; 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 tot, prime[MAXN], miu[MAXN]; int f[MAXN], g[MAXN], realn[MAXN], num[MAXN]; void init(int n) { realn[1] = miu[1] = 1; for (int i = 2; i <= n; i++) { if (f[i] == 0) { prime[++tot] = f[i] = realn[i] = i; num[i] = tot; miu[i] = -1; } for (int j = 1; j <= tot && prime[j] <= f[i]; j++) { int tmp = prime[j] * i; if (tmp > n) break; if (prime[j] == f[i]) realn[tmp] = realn[i], miu[tmp] = 0; else realn[tmp] = realn[i] * prime[j], miu[tmp] = -miu[i]; f[tmp] = prime[j]; } } for (int i = 2; i <= n; i++) { int tmp = i; while (f[tmp] != tmp) tmp /= f[tmp]; g[i] = tmp; } } int fa[MAXN]; int par(int x) { while (x != fa[x]) x = fa[x] = fa[fa[x]]; return x; } int main() { int n; read(n); vector <int> a(n + 1); for (int i = 1; i <= n; i++) read(a[i]); sort(a.begin(), a.end()); if (a[1] == 1) { printf("%d\n", 1); return 0; } int Max = a.back(); init(Max); for (int i = 1; i <= n; i++) a[i] = realn[a[i]]; sort(a.begin(), a.end()); Max = a.back(); static vector <int> factors[MAXN]; for (int i = 1; i <= Max; i++) for (int j = i; j <= Max; j += i) factors[j].push_back(i); static int cnt[MAXN]; for (int i = 1; i <= n; i++) for (auto j : factors[a[i]]) cnt[j]++; int ans = 0; vector <int> b; for (int i = 1; i <= n; i++) { int tmp = 0; for (auto j : factors[a[i]]) tmp += cnt[j] * miu[j]; if (tmp == 0) ans++; else b.push_back(a[i]); } b.erase(unique(b.begin(), b.end()), b.end()); a = b, n = a.size(); int oldn = n; for (int i = 0; i < n; i++) fa[i] = i; int limit = sqrt(a.back()); if (limit * limit <= a.back()) limit++; static int gcd[448][448]; for (int i = 0; i < limit; i++) for (int j = 0; j < limit; j++) gcd[i][j] = __gcd(i, j); sort(a.begin(), a.end(), [&] (int x, int y) {return g[x] < g[y]; }); static deque <pair <int, int> > p[MAXN]; vector <int> used; for (int i = 0; i < n; i++) if (g[a[i]] >= limit) { p[a[i] / g[a[i]]].push_back(make_pair(g[a[i]], i)); if (p[a[i] / g[a[i]]].size() == 1) used.push_back(a[i] / g[a[i]]); } for (int i = 0; i < n; i++) for (auto j : used) if (gcd[a[i] % j][j] == 1) { pair <int, int> tmp = make_pair(0, -1); while (!p[j].empty() && p[j].front().first != g[a[i]]) { tmp = p[j].front(); fa[par(tmp.second)] = par(i); p[j].pop_front(); } while (!p[j].empty() && p[j].back().first != g[a[i]]) { tmp = p[j].back(); fa[par(tmp.second)] = par(i); p[j].pop_back(); } if (tmp.second != -1) p[j].push_back(tmp); } while (!a.empty() && g[a.back()] >= limit) a.pop_back(); n = a.size(); static bitset <Q> edge[P], vis; for (int i = 0; i < n; i++) { vis.set(i); int tmp = a[i]; while (tmp != 1) { edge[num[f[tmp]]].set(i); tmp /= f[tmp]; } } for (int i = 0; i < n; i++) if (vis[i]) { int l = 0, r = 0; static int q[MAXN]; q[0] = i, vis[i] = false; while (l <= r) { int pos = q[l++]; bitset <Q> e = vis; int tmp = a[pos]; while (tmp != 1) { e &= ~edge[num[f[tmp]]]; tmp /= f[tmp]; } for (unsigned j = e._Find_first(); j < e.size(); j = e._Find_next(j)) { q[++r] = j, vis[j] = false; fa[par(pos)] = par(j); } } } for (int i = 0; i < oldn; i++) ans += par(i) == i; printf("%d\n", ans); return 0; }
**【DISTRING】**Distinct Rows in Submatrices
【思路要点】
- 枚举子矩形的左边界,将 行进行后缀排序,令结果为 。
- 从右向左依次考虑所有矩形的右边界,初始时,我们认为全部的 行是不同的,此时的贡献可以直接由组合数算出。每当右边界达到了某两个相邻的 的 时,我们合并 和 ,重新计算此时的贡献,我们需要减去包含与 相同的位置,不包含与 相同的位置 或是 不包含与 相同的位置,包含与 相同的位置的区间个数。
- 用并查集 配合启发式合并可以完成上述功能。
- 时间复杂度 。
【代码】
#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(""); } namespace SuffixArray { const int MAXN = 5e5 + 5; const int MAXLOG = 22; const int MAXC = 5e5; int sa[MAXN], rnk[MAXN], height[MAXN]; int Min[MAXN][MAXLOG], bit[MAXN], N; void init(int *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[a[i]]++; for (int i = 1; i <= n; i++) cnt[i] += cnt[i - 1]; for (int i = n; i >= 1; i--) sa[cnt[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 - x + 1; x = rnk[x], y = rnk[y]; if (x > y) swap(x, y); int tmp = bit[y - x]; return min(Min[x][tmp], Min[y - (1 << tmp)][tmp]); } } struct info {int pos, x, y; }; bool cmp(int x, int y) { return SuffixArray :: rnk[x] < SuffixArray :: rnk[y]; } bool cnp(info x, info y) { return x.pos < y.pos; } int n, m, tot, a[MAXN]; int pos[MAXN], f[MAXN], cnt; set <int> st[MAXN]; map <int, int> t; ll sum[MAXN]; int F(int x) { if (f[x] == x) return x; else return f[x] = F(f[x]); } ll sqr(int x) { return x * (x + 1ll) / 2; } int main() { read(n), read(m); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { read(a[++tot]); if (!t.count(a[tot])) t[a[tot]] = ++cnt; a[tot] = t[a[tot]]; } SuffixArray :: init(a, tot); ll ans = 0; for (int j = 1; j <= m; j++) { for (int i = 1, p = j; i <= n; i++, p += m) pos[i] = p; sort(pos + 1, pos + n + 1, cmp); for (int i = 1; i <= n; i++) { f[i] = i; st[i].clear(); st[i].insert(0); st[i].insert(i); st[i].insert(n + 1); sum[i] = sqr(i - 1) + sqr(n - i); } static info b[MAXN]; for (int i = 1; i <= n - 1; i++) { int tmp = min(SuffixArray :: lcp(pos[i], pos[i + 1]), m - j + 1); b[i] = (info) {tmp + j - 1, (pos[i] - 1) / m + 1, (pos[i + 1] - 1) / m + 1}; } sort(b + 1, b + n, cnp); b[n].pos = m; ll now = n * (n + 1ll) * (n + 2ll) / 6; for (int i = n - 1; i >= 1; i--) { ans += now * (b[i + 1].pos - b[i].pos); int tx = F(b[i].x), ty = F(b[i].y); if (st[tx].size() < st[ty].size()) swap(tx, ty); now += sum[tx], now += sum[ty]; for (auto pos : st[ty]) if (pos != 0 && pos != n + 1) { auto tmp = st[tx].insert(pos).first; auto pre = tmp, suf = tmp; pre--, suf++; sum[tx] -= sqr((*suf) - (*pre) - 1); sum[tx] += sqr((*suf) - (*tmp) - 1); sum[tx] += sqr((*tmp) - (*pre) - 1); } f[ty] = tx; now -= sum[tx] + n * (n + 1ll) / 2; } ans += now * (b[1].pos - j + 1); } writeln(ans); return 0; }
**【HMAPPY】**Appy and Balloons
【思路要点】
- 二分答案,贪心检验正确性。
- 时间复杂度 。
【代码】
#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 n; ll m, a[MAXN], b[MAXN]; bool valid(ll mid) { ll used = 0; for (int i = 1; i <= n; i++) { ll saved = mid / b[i]; used += max(0ll, a[i] - saved); } return used <= m; } int main() { read(n), read(m); for (int i = 1; i <= n; i++) read(a[i]); for (int i = 1; i <= n; i++) read(b[i]); ll l = 0, r = 1e18; while (l < r) { ll mid = (l + r) / 2; if (valid(mid)) r = mid; else l = mid + 1; } writeln(l); return 0; }
**【MINDSUM】**Minimize Digitsum
【思路要点】
- 一个 以内的数经过至多 次数位和操作就会变成 以内的一个数。
- 数位和操作不会改变一个数模 的余数。
- 因此 次操作内,我们可以取到 至 中任意一个可能取到的数。
- 因此我们直接暴力搜索 层的决策即可。
- 单组数据时间复杂度 ,取 。
【代码】
#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 ans, s, x, y; ll f(ll x) { int ans = 0; while (x != 0) { ans += x % 10; x /= 10; } return ans; } void work(ll x, ll sum) { if (x < ans) { ans = x; s = sum; } else if (x == ans) chkmin(s, sum); if (sum >= 21) return; work(x + y, sum + 1); work(f(x), sum + 1); } int main() { int T; read(T); while (T--) { read(x), read(y); ans = x, s = 0; work(x, 0); printf("%lld %lld\n", ans, s); } return 0; }
**【SURCHESS】**Chef and Surprise Chessboard
【思路要点】
- 枚举一个正方形的左上角以及左上角的颜色,从小到大枚举其边长,通过部分和预处理,我们可以在 的时间内知道需要的修改次数。
- 再用前缀和处理一下答案数组即可。
- 当 同阶时,时间复杂度 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 205; 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, m, q; char s[MAXN][MAXN]; int ans[MAXN * MAXN]; int row[MAXN][MAXN][MAXN][4]; int col[MAXN][MAXN][MAXN][4]; int main() { read(n), read(m); for (int i = 1; i <= n; i++) scanf("\n%s", s[i] + 1); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) for (int k = j; k <= m; k++) { memcpy(row[i][j][k], row[i][j][k - 1], sizeof(row[i][j][k])); row[i][j][k][(k % 2) * 2 + (s[i][k] == '1')]++; } for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) for (int k = j; k <= n; k++) { memcpy(col[i][j][k], col[i][j][k - 1], sizeof(col[i][j][k])); col[i][j][k][(k % 2) * 2 + (s[k][i] == '1')]++; } for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { int now1 = 0, now2 = 0; for (int len = 1, ti = i, tj = j; ti <= n && tj <= m; len++, ti++, tj++) { now1 += row[ti][j][tj - 1][((len + j + 1) % 2) * 2 + 1]; now1 += row[ti][j][tj - 1][((len + j) % 2) * 2]; now2 += row[ti][j][tj - 1][((len + j) % 2) * 2 + 1]; now2 += row[ti][j][tj - 1][((len + j + 1) % 2) * 2]; now1 += col[tj][i][ti - 1][((len + i + 1) % 2) * 2 + 1]; now1 += col[tj][i][ti - 1][((len + i) % 2) * 2]; now2 += col[tj][i][ti - 1][((len + i) % 2) * 2 + 1]; now2 += col[tj][i][ti - 1][((len + i + 1) % 2) * 2]; now1 += s[ti][tj] == '1'; now2 += s[ti][tj] == '0'; chkmax(ans[now1], len); chkmax(ans[now2], len); } } for (int i = 1; i <= n * m; i++) chkmax(ans[i], ans[i - 1]); read(q); while (q--) { int x; read(x); chkmin(x, n * m); writeln(ans[x]); } return 0; }
**【TREEWALK】**Walk on Tree
【思路要点】
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 3005; const int MAXM = 9005; 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(""); } namespace LinearSequence { const int MAXN = 9005; const int MAXLOG = 31; const int P = 998244353; vector <int> a[MAXN]; int cnt, delta[MAXN], fail[MAXN]; int k, h[MAXN], now[MAXLOG][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 times(int *res, int *x, int *y) { static int tmp[MAXN]; memset(tmp, 0, sizeof(tmp)); for (int i = 0; i <= k - 1; i++) for (int j = 0; j <= k - 1; j++) tmp[i + j] = (tmp[i + j] + 1ll * x[i] * y[j]) % P; for (int i = 2 * k - 2; i >= k; i--) { int val = tmp[i]; tmp[i] = 0; for (unsigned j = 0; j < a[cnt].size(); j++) tmp[i - j - 1] = (tmp[i - j - 1] + 1ll * val * a[cnt][j]) % P; } memcpy(res, tmp, sizeof(tmp)); } void init(int n, int *val) { for (int i = 0; i <= cnt; i++) a[i].clear(); cnt = 0; for (int i = 1; i <= n; i++) { delta[i] = val[i]; for (unsigned j = 0; j < a[cnt].size(); j++) delta[i] = (delta[i] - 1ll * a[cnt][j] * val[i - j - 1] % P + P) % P; if (delta[i] == 0) continue; fail[cnt] = i; if (cnt == 0) { a[++cnt].resize(i); continue; } int mul = 1ll * delta[i] * power(delta[fail[cnt - 1]], P - 2) % P; a[cnt + 1].resize(i - fail[cnt - 1] - 1); a[cnt + 1].push_back(mul); for (unsigned j = 0; j < a[cnt - 1].size(); j++) a[cnt + 1].push_back(1ll * a[cnt - 1][j] * (P - mul) % P); if (a[cnt + 1].size() < a[cnt].size()) a[cnt + 1].resize(a[cnt].size()); for (unsigned j = 0; j < a[cnt].size(); j++) a[cnt + 1][j] = (a[cnt + 1][j] + a[cnt][j]) % P; cnt++; } //cerr << a[cnt].size() << endl; if (n < 2 * a[cnt].size() + 5) { cerr << "Failed!" << endl; return; } memset(now, 0, sizeof(now)); now[0][1] = 1; k = a[cnt].size(); for (int i = 1; i <= 2 * k; i++) h[i] = val[i]; for (int p = 1; p < MAXLOG; p++) times(now[p], now[p - 1], now[p - 1]); } void query(int *res, int n) { if (n <= k) assert(false); res[0] = 1; n -= k; for (int p = 0; p < MAXLOG; p++) { int tmp = 1ll << p; if (n & tmp) times(res, res, now[p]); } } } vector <int> a[MAXN]; int dp[MAXM][MAXN]; int n, root, k; 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); } read(root), read(k); dp[0][root] = 1; int goal = 2 * n + 15; for (int p = 1; p <= goal; p++) { for (int i = 1; i <= n; i++) { for (auto j : a[i]) { dp[p][i] += dp[p - 1][j]; if (dp[p][i] >= P) dp[p][i] -= P; } } } if (k <= goal) { for (int i = 1; i <= n; i++) printf("%d ", dp[k][i]); return 0; } int tot = 0; static int tmp[MAXM]; for (int p = 0; p <= goal; p++) { int val = 0; for (int i = 1; i <= n; i++) val = (97ll * val + dp[p][i]) % P; tmp[++tot] = val; } static int res[MAXM]; LinearSequence :: init(tot, tmp); LinearSequence :: query(res, k + 1); int len = LinearSequence :: k; for (int i = 1; i <= n; i++) { int ans = 0; for (int j = 0; j <= len - 1; j++) ans = (ans + 1ll * res[j] * dp[j + len - 1][i]) % P; printf("%d ", ans); } return 0; }