statement:https://www.jisuanke.com/contest/5529
赛中过题: A C F
M. Kill the tree
给一棵树,求每棵子树的重心.
考虑从子树的重心转移到根的重心,直接暴力往上跳.
由于路径不相交,这样做的复杂度为
#include<bits/stdc++.h> using namespace std; typedef vector<int> VI; typedef long long ll; #define empb emplace_back #define sz(x) (int)(x).size() const int N = 2e5 + 7; VI E[N]; int ans[N], fa[N], sz[N]; void dfs(int u, int f){ fa[u] = f; ans[u] = u; sz[u] = 1; for(auto &v : E[u]){ if(v == f) continue; dfs(v, u); sz[u] += sz[v]; } for(auto &v : E[u]){ if(v == f) continue; int t = ans[v]; while(sz[t] * 2 < sz[u]) t = fa[t]; if(sz[t] < sz[ans[u]]) ans[u] = t; } } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int n; cin >> n; for(int i = 1, u, v; i < n; i++){ cin >> u >> v; E[u].empb(v); E[v].empb(u); } dfs(1, 0); for(int i = 1; i <= n; i++){ if(sz[ans[i]] * 2 == sz[i]) { int a1 = ans[i], a2 = fa[ans[i]]; if(a1 > a2) swap(a1, a2); cout << a1 << ' ' << a2 << '\n'; } else cout << ans[i] << '\n'; } return 0; }
L.Loli, Yen-Jen, and a cool problem
广义后缀自动机裸题(据说bfs建广义后缀自动机的link转移较少).
#include<bits/stdc++.h> using namespace std; typedef vector<int> VI; typedef long long ll; #define empb emplace_back #define SZ(x) (int)(x).size() const int N = 3e5 + 7; char s[N]; int n, q; struct SAM { static const int M = N << 1; int nxt[M][26], len[M], fa[M], tot, last; int newnode(int l = 0) { memcpy(nxt[++tot], nxt[l], sizeof nxt[0]); return tot; } void init() { tot = 0; len[0] = -1; last = newnode(); } int extend(int p, int ch, int idx) { int f = !!nxt[p][ch]; // f == 1 for exSAM int np = f ? nxt[p][ch] : newnode(); if(!f) len[np] = len[p] + 1; for(; !f && p && !nxt[p][ch]; p = fa[p]) nxt[p][ch] = np; if(!p) return fa[np] = 1, np; int q = nxt[p][ch]; if(len[p] + 1 == len[q]) { if(!f) fa[np] = q; } else { int nq = newnode(q); len[nq] = len[p] + 1; fa[nq] = fa[q]; fa[np] = fa[q] = nq; for(; nxt[p][ch] == q; p = fa[p]) nxt[p][ch] = nq; if(f) np = nq; } return np; } int c[N], topo[M]; void toposort(int n) { memset(c + 1, 0, tot * 4); for(int i = 1; i <= tot; i++) c[len[i]]++; for(int i = 1; i <= n; i++) c[i] += c[i - 1]; for(int i = 1; i <= tot; i++) topo[c[len[i]]--] = i; } int anc[M][20], w[M]; void build() { toposort(n); for(int i = tot; i; i--) { w[fa[topo[i]]] += w[topo[i]]; } for(int i = 1; i <= tot; i++) anc[i][0] = fa[i]; for(int i = 1; i < 20; i++) for(int j = 1; j <= tot; j++) anc[j][i] = anc[anc[j][i-1]][i-1]; } int query(int u, int l) { for(int i = 19; ~i; i--) if(len[anc[u][i]] >= l) u = anc[u][i]; return w[u]; } } sam; vector<int> E[N]; int pos[N]; void dfs(int u, int l) { sam.w[pos[u]=l=sam.extend(l,s[u]-'A',u)]++; for(auto &v : E[u]) dfs(v, l); } int main() { #ifdef local freopen("in.txt", "r", stdin); #endif ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); sam.init(); cin >> n >> q >> s + 1; for(int i = 2, f; i <= n; i++) cin >> f, E[f].empb(i); dfs(1, 1); sam.build(); while(q--) { int x, l; cin >> x >> l; cout << sam.query(pos[x], l) << '\n'; } return 0; }
E.Multiply
大数分解.
#include<bits/stdc++.h> using namespace std; typedef long double ldb; typedef int64_t ll; typedef uint64_t ull; #define sz(x) (int)(x).size() #define all(x) (x).begin(),(x).end() const ldb eps = 1e-8; ull mul_mod(ull a, ull b, ull m) { if(a >= m) a %= m; if(b >= m) b %= m; ull res = a*b - ull((ldb)a*b/m+eps)*m; return ll(res) < 0 ? res + m : res; return (__int128) a * b % m; } ull power_mod(ull a, ull b, ull m) { ull res = 1; for(; b; b >>= 1, a = mul_mod(a, a, m)) if(b & 1) res = mul_mod(res, a, m); return res; } bool miller_robin(ull a, ull n) { if(a >= n) return 1; ull s = __builtin_ctz(n - 1), i = 0, d = n >> s; ull t = power_mod(a, d, n); while(t != 1 && t != n - 1 && i < s) t = mul_mod(t, t, n), i++; return t == n - 1 || !i; } bool isprime(ull n) { if(n <= 1) return false; if(n % 6 % 4 != 1) return n < 4; static vector<ull> t = {2, 325, 9375, 28178, 450775, 9780504, 1795265022}; for(auto &e : t) if(!miller_robin(e, n)) return false; return true; } mt19937_64 gen(time(0)); vector<ull> pfactor(ull n) { if(n == 1) return {}; if(isprime(n)) return {n}; while(1) { ull c = gen() % (n - 1) + 1; auto f = [n,c](ull x) { return (mul_mod(x,x,n)+c)%n;}; ull x = gen() % n, y = f(x); while(x != y) { ull d = __gcd(x - y + n, n); if(d != 1) { auto l = pfactor(d), r = pfactor(n / d); l.insert(l.end(), all(r)); return l; } x = f(x); y = f(f(y)); } } assert(false); } ull calc(const vector<ull>&a, ull y, ull p) { ull res = 0; while(y /= p) res += y; for(int i = 0; i < sz(a); i++) { ull t = a[i]; while(t /= p) res -= t; } return res; } int main() { #ifdef local freopen("in.txt", "r", stdin); #endif ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int _; cin >> _; while(_--) { int n; cin >> n; ull x, y; cin >> x >> y; vector<ull> a(n); for(int i = 0; i < n; i++) cin >> a[i]; ull res = LLONG_MAX; auto px = pfactor(x); sort(all(px)); for(int i = 0, j = 0; i < sz(px); i = j) { while(j < sz(px) && px[j] == px[i]) j++; ull num = j - i; ull allp = calc(a, y, px[i]); res = min(res, allp / num); } cout << res << '\n'; } return 0; }
H.Yuuki and a problem
给一个序列,有
次操作,
1.
2.询问区间最小不能用子集和表示出来的数.
结论:若能表示出
之间的所有数,那么
能表示出
中的所有数.
注意到这个递增过程类似斐波那契数列,因此,我们可以用线段树树套树状数组来维护二维区间和(如果没有修改操作,可以用可持久化线段树).
总时间复杂度为.
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1 << 18 | 7; const int m = 2e5; int root[N], a[N], ch[N*80][2], n, q, tot; ll val[N*80]; void init() { tot = 0;} int newnode() { val[++tot] = 0; memset(ch[tot], 0, sizeof ch[0]); return tot; } void update(int x, int v, int &o, int l, int r){ if(!o) o = newnode(); val[o] += v; if(l == r) return; int mid = (l + r) >> 1; if(mid >= x) update(x, v, ch[o][0], l, mid); else update(x, v, ch[o][1], mid + 1, r); } ll query(int ql, int qr, int o, int l, int r){ if(!o || ql <= l && r <= qr) return val[o]; ll res = 0; int mid = (l + r) >> 1; if(ql <= mid) res += query(ql, qr, ch[o][0], l, mid); if(qr > mid) res += query(ql, qr, ch[o][1], mid + 1, r); return res; } void update(int x, int y, int v) { for(; x <= n; x += x&-x) update(y, v, root[x], 1, m); } ll query(int x, int y, int ql, int qr){ if(ql > qr) return 0; ll res = 0; while(x != y) { if(x > y) res -= query(ql, qr, root[x], 1, m), x -= x&-x; else res += query(ql, qr, root[y], 1, m), y -= y&-y; } return res; } int main() { #ifdef local freopen("in.txt", "r", stdin); #endif ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); init(); cin >> n >> q; for(int i = 1; i <= n; i++) root[i] = 0; for(int i = 1; i <= n; i++) { cin >> a[i]; update(i, a[i], a[i]); } while(q--) { int op; cin >> op; if(op == 1) { int x, y; cin >> x >> y; update(x, a[x], -a[x]); a[x] = y; update(x, a[x], a[x]); } else { int l, r; cin >> l >> r; l--; ll x = -1, y = 0; while(1) { ll dt = query(l, r, min(x+2ll,(ll)m+1), min(y+1ll,(ll)m)); if(!dt) break; x = y, y += dt; } cout << y + 1 << '\n'; } } return 0; }