intmain(){ int n = read; read.operatorint(), read.operatorint(), read.operatorint(); int B = 32; ull FULL = (1llu << B) - 1; for (int i = 1; i <= n; i++) { int o = read; if (o == 1) { int ix = read, k = read; if (ix >= 0) { ull x = ull(ix); x <<= k % B; k /= B; while (x) { data[k] += x; x = data[k] >> B; data[k] &= FULL; ++k; } } else { ull x = ull(-ix); x <<= k % B; k /= B; while (x) { data[k] -= x; x = data[k] >> B; if (x) x = (1llu << B) - x; data[k] &= FULL; ++k; } } } if (o == 2) { int k = read; printf("%llu\n", data[k / B] >> (k % B) & 1); } } }
autofind(int k){ auto it = -- set.upper_bound(k << 1 | 1); int k2 = *it >> 1, x = *it & 1; if (k == k2) return it; return set.insert(k << 1 | x).first; }
voidmodi(int k, int t){ auto p = find(k), q = p; while ((*q & 1) == t) ++ q; auto r = find((*q >> 1) + 1); int tmp = *p, tmq = *q; set.erase(p, r); set.insert(tmp ^ 1); set.insert(tmq ^ 1); }
intmain(){ int n = read; read.operatorint(), read.operatorint(), read.operatorint(); set.insert(0 << 1 | 0); for (int i = 1; i <= n; i ++) { int o = read; if (o == 1) { int x = read, off = read; if (x >= 0) { for (int k = 0; k < maxk; k ++) if (x >> k & 1) modi(off + k, 1); } else { x = -x; for (int k = 0; k < maxk; k ++) if (x >> k & 1) modi(off + k, 0); } } if (o == 2) { auto p = find(read); printf("%d\n", *p & 1); } } }
然后没什么思路了,感觉应该还是要压位,但是维护连续段后似乎难以直接压位?想到
std::insert 可以提供 hint 做到 \(O(1)\) ,于是写了个带 hint
的版本,得了 76 分。(代码略)
autofind(int k){ auto it = hint ? set_hint : -- set.upper_bound(k << 1 | 1); if (hint) { while (it != set.end() and (*it >> 1) <= k) ++ it; -- it; } int k2 = *it >> 1, x = *it & 1; if (k == k2) return it; return set.insert(it, k << 1 | x); }
voidmodi(int k, int t){ auto p = find(k), q = p; while ((*q & 1) == t) ++ q; auto r = find((*q >> 1) + 1); int tmp = *p, tmq = *q; set.erase(p --, r); set_hint = set.insert(p, tmp ^ 1); set.insert(set_hint, tmq ^ 1); hint = 1; }
intmain(){ int n = read; read.operatorint(), read.operatorint(), read.operatorint(); set.insert(-1); set.insert(0 << 1 | 0); for (int i = 1; i <= n; i ++) { int o = read; if (o == 1) { int x = read, off = read; if (x >= 0) { hint = 0; for (int k = 0; k < maxk; k ++) if (x >> k & 1) modi(off + k, 1); } else { hint = 0; x = -x; for (int k = 0; k < maxk; k ++) if (x >> k & 1) modi(off + k, 0); } } if (o == 2) { /* hint = 0; */ int k = read; auto p = -- set.upper_bound(k << 1 | 1); printf("%d\n", *p & 1); } } }
蚯蚓排队
刚开始有个启发式合并 + SAM 的想法,但是发现由于 SAM
只能在末尾加字符而不能加在开头,启发式合并是不可行的。
voidforce(int i, int j, int coe){ ull shit = 0; for (int x = i, k = 1; x and k < Maxk; k ++, x = pre[x]) { shit += ull(a[x]) * po[k - 1]; ull now = shit; for (int y = j, k2 = k + 1; y and k2 <= Maxk; k2 ++, y = nxt[y]) map[now = now * base + ull(a[y])] += coe; } }
intmain(){ po[0] = 1; for (int i = 1; i <= Maxk; i ++) po[i] = po[i - 1] * base; int n = read, q = read; for (int i = 1; i <= n; i ++) ++ map[ull(a[i] = read)]; while (q --) { int o = read; if (o == 1) { int i = read, j = read; nxt[i] = j; pre[j] = i; force(i, j, 1); } if (o == 2) { int i = read, j = nxt[i]; force(i, j, -1); nxt[i] = pre[j] = 0; } if (o == 3) { scanf("%s", s + 1); int len = int(strlen(s + 1)), K = read; ull now = 0; for (int i = 1; i <= K; i ++) now = now * base + ull(s[i] - '0'); ll ans = map[now]; for (int i = K + 1; i <= len; i ++) { now = now * base + ull(s[i] - '0'); now -= ull(s[i - K] - '0') * po[K]; (ans *= map[now]) %= mod; } printf("%lld\n", ans); } } }
只会暴力,上面的算法主要问题是 map 太慢,用数组分摊给它优化一波:
1 2 3
const ull B = 24, Bl = (1llu << B) - 1; std::map<ull, int> Map[1 << B]; int &map(ull x){ return Map[x & Bl][x >> B]; }
ll solve(int N, int K, ll q){ if (K < 0) return0; h[0] = mod + 1 - q; for (int x = 1; x <= K; x ++) h[x] = h[x - 1] * q % mod; std::fill(f[0], f[0] + K + 2, 1); for (int n = 1; n <= N; n ++) { std::fill(f[n], f[n] + K + 2, 0); for (int m = 0; n * m <= K; m ++) { for (int i = 1; i <= n; i ++) for (int x = m; n * x <= K; x ++) (f[n][m] += h[x] * f[i - 1][x + 1] % mod * f[n - i][x]) %= mod; } } return f[N][0]; }
intmain(){ int n = read, m = read, q = read; int pp = 0; for (int i = 1; i <= n; i ++) { int a = read, s = read, c = read, x = read; p[++ pp] = par(a, c - 1); p[++ pp] = par(a + s, 1); } std::sort(p + 1, p + pp + 1); p[0] = par(0, 1000000000); for (int i = 1; i <= 100000; i ++) { ans[i] = ans[i - 1]; for (int j = 1; j <= m; j ++) { while (!p[pp].second) -- pp; -- p[pp].second; ans[i] += p[pp].first; } } while (q --) { int d = read; printf("%lld\n", ans[d]); } }
constint maxn = 100005; ll ans[maxn * 10]; structcai { int a, c, x, t; intlas(){ if (t) return t; return x ? (c + x - 1) / x : 1000000000; } };
booloperator < (cai a, cai b) { return a.a == b.a ? a.las() < b.las() : a.a < b.a; }
int M, tim[maxn], tp, minT; boolcheck(int t){ return t >= minT; }
voidadd(int t){ tim[++ tp] = t; std::sort(tim + 1, tim + tp + 1); // 懒 minT = tp / M * M; while (minT >= 0and tim[minT] != minT / M) minT -= M; minT = minT >= 0 ? tim[minT] + 1 : 1; }
intmain(){ int K = 1000; int n = read, m = read, q = read; std::priority_queue<cai> qu; M = m; qu.push({0, 1000000000, 0, 1000000000});
for (int i = 1; i <= n; i ++) { int a = read, s = read, c = read, x = read; cai tmp = {a, c - 1, x, 0}; qu.push(tmp); ++ tmp.c; qu.push({s + a, 1, 0, tmp.las()}); }
for (int i = 1; i <= K * m; i ++) { cai tmp = qu.top(); qu.pop(); while (tmp.c <= 0or !check(tmp.las())) tmp = qu.top(), qu.pop(); ans[i] = ans[i - 1] + tmp.a; add(tmp.las()); if (tmp.c > 1) { -- tmp.c; qu.push(tmp); } }
while (q --) printf("%lld\n", ans[int(read) * m]); }
intmain(){ int n = read, q = read; ll ans = -1; for (int i = 1; i <= n; i ++) read(P[i].x, P[i].y); while (q --) { int m = read; std::fill(mark, mark + n + 1, 0); for (int i = 1; i <= m; i ++) mark[1 + (ans + int(read)) % n] = 1; m = 0; for (int i = 1; i <= n; i ++) if (!mark[i]) p[++ m] = P[i]; std::sort(p + 1, p + m + 1, [] (point a, point b) { return a.x == b.x ? a.y < b.y : a.x < b.x; }); int p1 = 0; for (int i = 1; i <= m; i ++) { while (p1 >= 2andcross(st1[p1] - st1[p1 - 1], p[i] - st1[p1]) >= 0) -- p1; st1[++ p1] = p[i]; } std::sort(p + 1, p + m + 1, [] (point a, point b) { return a.x == b.x ? a.y > b.y : a.x < b.x; }); int p2 = 0; for (int i = 1; i <= m; i ++) { while (p2 >= 2andcross(st2[p2] - st2[p2 - 1], p[i] - st2[p2]) <= 0) -- p2; st2[++ p2] = p[i]; } while (p2) st1[++ p1] = st2[p2 --]; st1[p1 + 1] = st1[1]; ans = 0; for (int i = 2; i <= p1; i ++) ans -= cross(st1[i] - st1[1], st1[i + 1] - st1[i]); printf("%lld\n", ans); } }
intfind(int x){ return fa[x] == x ? x : fa[x] = find(fa[x]); }
voiddijkstra(int s, int n);
intmain(){ #ifndef LOCAL freopen("return.in", "r", stdin); freopen("return.out", "w", stdout); #endif
int T = read; while (T --) { int n = read, m = read; for (int u = 1; u <= n; u ++) G[u].clear(); for (int i = 1; i <= m; i ++) { int u = read, v = read, w = read, h = read; G[u].push_back({v, w}); G[v].push_back({u, w}); e2[i] = {u, v, h}; } dijkstra(1, n);
int q = read, K = read, H = read; if (K == 1) return0; for (int i = 1; i <= q; i ++) { int s = read, h = read; qu[i] = {s, h, i}; }
std::sort(e2 + 1, e2 + m + 1, [] (Edge2 a, Edge2 b) { return a.h > b.h; }); std::sort(qu + 1, qu + q + 1, [] (Query a, Query b) { return a.h > b.h; });
for (int u = 1; u <= n; u ++) fa[u] = u;
for (int i = 1, j = 1; i <= q; i ++) { while (j <= m and e2[j].h > qu[i].h) { int u = find(e2[j].u), v = find(e2[j].v); ++ j; if (dis[u] < dis[v]) fa[v] = u; else fa[u] = v; } ans[qu[i].id] = dis[find(qu[i].s)]; }
for (int i = 1; i <= q; i ++) printf("%d\n", ans[i]); } }
强制在线似乎可以直接把加边的过程可持久化,来一手可持久化并查集?
太麻烦了没写,还可以用 kruskarl
重构树,对于询问倍增到重构树上的点,然后求个子树 min
即可,写的时候重构树的点数只开到了 n ,WA 了几次。
intfind(int x){ return top[x] == x ? x : top[x] = find(top[x]); }
voiddijkstra(int s, int n){ std::priority_queue<par> q; std::fill(dis, dis + n + 1, 2000000000); dis[s] = 0; q.push(par(0, s)); while (!q.empty()) { int u = q.top().second, d = -q.top().first; q.pop(); if (d > dis[u]) continue; for (Edge e : G[u]) if (dis[u] + e.w < dis[e.v]) { dis[e.v] = dis[u] + e.w; q.push(par(-dis[e.v], e.v)); } } }
intmain(){ #ifndef LOCAL freopen("return.in", "r", stdin); freopen("return.out", "w", stdout); #endif
int T = read; while (T --) { int n = read, m = read; for (int u = 1; u <= n; u ++) G[u].clear(); for (int i = 1; i <= m; i ++) { int u = read, v = read, w = read, h = read; G[u].push_back({v, w}); G[v].push_back({u, w}); e2[i] = {u, v, h}; } dijkstra(1, n);
std::sort(e2 + 1, e2 + m + 1, [] (Edge2 a, Edge2 b) { return a.h > b.h; }); for (int u = 1; u <= n; u ++) top[u] = u, minh[u] = 2000000000;
int np = n; for (int i = 1; i <= m; i ++) { int u = find(e2[i].u), v = find(e2[i].v); if (u == v) continue; ++ np; fa[0][u] = fa[0][v] = np; fa[0][np] = 0; top[u] = top[v] = top[np] = np; minh[np] = e2[i].h; dis[np] = std::min(dis[u], dis[v]); }
for (int x = np; x; x --) for (int k = 1; k < Maxk; k ++) fa[k][x] = fa[k - 1][fa[k - 1][x]];
int q = read, K = read, S = read, ans = 0; if (!n) return1; while (q --) { int x = read, h = read; if (K) x = 1 + (x + ans - 1) % n, h = (h + ans) % (S + 1); for (int k = Maxk - 1; k >= 0; k --) if (fa[k][x] and minh[fa[k][x]] > h) x = fa[k][x]; printf("%d\n", ans = dis[x]); } } }
intmain(){ #ifndef LOCAL freopen("inverse.in", "r", stdin); freopen("inverse.out", "w", stdout); #endif
int T = read; while (T --) { int n = read; if (n > maxn) { for (int i = 0; i < n; i ++) read.operatorint(); ll ans = 1; for (int i = 1; i <= n; i ++) { (ans *= 4 * i - 2) %= mod; (ans *= power(i + 1, -1)) %= mod; } -- ans; printf("%lld\n", ans); continue; } for (int i = 0; i < n; i ++) p[i] = read - 1; g[0] = 1; for (int S = 1; S < (1 << n); S ++) { int i = -1, max = 0, X = 0; for (int x = 0; x < n; x ++) if (S >> x & 1) ++ i, max = x; while (S >> X & 1) ++ X; f[S] = g[S] = 0; for (int x = 0; x < n; x ++) if (S >> x & 1) { bool ok = 1; if (x <= i) ok &= x < X; if (x >= i) ok &= x == max; if (ok) { f[S] += f[S ^ (1 << x)]; if (x == p[i]) g[S] += g[S ^ (1 << x)]; if (x > p[i]) f[S] += g[S ^ (1 << x)]; } } f[S] %= mod; } printf("%lld\n", f[(1 << n) - 1]); } }
ll _path (int x, int y) { if (x < 0or y < 0) return0; return fac[x + y] * ifac[x] % mod * ifac[y] % mod; }
ll path(int x0, int y0, int x1, int y1){ ll tmp = _path(x1 - x0, y1 - y0) - _path(x1 - x0 - 1, y1 - y0 + 1); return tmp < 0 ? tmp + mod : tmp; }
intmain(){ #ifndef LOCAL freopen("inverse.in", "r", stdin); freopen("inverse.out", "w", stdout); #endif
int N = 2000; fac[0] = 1; for (int i = 1; i <= N; i ++) fac[i] = fac[i - 1] * i % mod; ifac[N] = power(fac[N], -1); for (int i = N; i; i --) ifac[i - 1] = ifac[i] * i % mod;
int T = read; while (T --) { int n = read; for (int i = 1; i <= n; i ++) p[i] = read; ll ans = 0; std::fill(vis + 1, vis + n + 1, 0); std::set<int> set; for (int i = 1; i <= n; i ++) set.insert(i); int m = 0, x = 0; for (int i = 1; i <= n; i ++) { for (int j = std::max(p[i], x) + 1; j <= n; j ++) if (!vis[j]) { int _m = std::max(m, j); set.erase(j); int k = *set.begin(); set.insert(j); if (k < x or (k < j and j < m)) continue; ans += path(_m, i, n, n); } vis[p[i]] = 1; if (p[i] < x) break; if (p[i] < m) x = p[i]; else m = p[i]; set.erase(p[i]); } printf("%lld\n", ans % mod); } }
intmain(){ #ifndef LOCAL freopen("name.in", "r", stdin); freopen("name.out", "w", stdout); #endif
scanf("%s", s + 1); int n = int(strlen(s + 1)); for (int i = 1, las = 1; i <= n; i ++) las = insert(1, las, s[i] - 'a'); tpos[0] = ++ cp;
int q = read; while (q --) { scanf("%s", t + 1); int l = read, r = read, m = int(strlen(t + 1)); if (l != 1and r != n) return1; cp = tpos[0]; memset(ch[cp], 0, sizeof ch[cp]); for (int i = 1; i <= m; i ++) tpos[i] = insert(tpos[0], tpos[i - 1], t[i] - 'a'); std::fill(vis + tpos[0], vis + cp + 1, 0);
ll ans = 0; for (int i = 1, u = 1, le = 0; i <= m; i ++) { int x = t[i] - 'a'; while (u and !ch[u][x]) u = fa[u], le = len[u]; if (u) u = ch[u][x], ++ le; else u = 1; int v = tpos[i], vlen = len[v], flen = vlen; while (!vis[v]) vis[v] = 1, v = fa[v], flen = len[v]; ans += vlen - std::max(flen, le); } printf("%lld\n", ans); } }
这个做法推广到任意区间也不难,把 \(s\) 的 SAM 节点的 right
集合处理出来,然后每次算贡献的时候查 right
集合在区间内最靠右的点然后得到实际匹配长度即可。但是 right
集合不能显式地建出来,一般有两种方式,一个是离线下来挂在对应位置然后 set
启发式合并,还有一种是线段树合并。后者唯一的缺点是空间开销较大,但是其他地方都很优秀,并且还能支持更多操作。
constint maxn = 500005, maxd = 2000005, maxc = 26; std::vector<int> G[maxd]; char s[maxn], t[maxn]; int ch[maxd][maxc], fa[maxd], len[maxd], cp = 1; bool vis[maxd]; int spos[maxn], tpos[maxn]; int seg[maxd]; structTree { int lti, rti; int max; } pool[maxn * 60]; #define self pool[now]
int pp; inlineintnewnode(){ return ++ pp; }
voidmerge(int &now, int an, int L, int R){ if (!an) return; if (!now) return now = an, void(); pool[newnode()] = self; now = pp; self.max = std::max(self.max, pool[an].max); int M = (L + R) >> 1; merge(self.lti, pool[an].lti, L, M); merge(self.rti, pool[an].rti, M + 1, R); }
voidlain(int &now, int L, int R, int p){ if (!now) now = newnode(); self.max = std::max(self.max, p); if (L == R) return; int M = (L + R) >> 1; if (p <= M) lain(self.lti, L, M, p); elselain(self.rti, M + 1, R, p); }
intquery(int now, int L, int R, int l, int r){ if (r < L or l > R) return0; if (l <= L and R <= r) return self.max; int M = (L + R) >> 1; return std::max(query(self.lti, L, M, l, r), query(self.rti, M + 1, R, l, r)); }
intinsert(int rt, int pre, int x){ int now = ++ cp; len[now] = len[pre] + 1; memset(ch[now], 0, sizeof ch[now]); while (pre and !ch[pre][x]) ch[pre][x] = now, pre = fa[pre]; if (pre) { int preto = ch[pre][x]; if (len[preto] == len[pre] + 1) fa[now] = preto; else { int sp = ++ cp; len[sp] = len[pre] + 1; fa[sp] = fa[preto]; memcpy(ch[sp], ch[preto], sizeof ch[sp]); while (pre and ch[pre][x] == preto) ch[pre][x] = sp, pre = fa[pre]; fa[now] = fa[preto] = sp; } } else fa[now] = rt; return now; }
voiddfs(int u, int n){ for (int v : G[u]) { dfs(v, n); merge(seg[u], seg[v], 1, n); } }
intmain(){ #ifndef LOCAL freopen("name.in", "r", stdin); freopen("name.out", "w", stdout); #endif
scanf("%s", s + 1); int n = int(strlen(s + 1)); for (int i = 1, las = 1; i <= n; i ++) { las = insert(1, las, s[i] - 'a'); lain(seg[las], 1, n, i); } for (int i = 2; i <= cp; i ++) G[fa[i]].push_back(i); dfs(1, n);
tpos[0] = ++ cp;
int q = read; while (q --) { scanf("%s", t + 1); int l = read, r = read, m = int(strlen(t + 1)); cp = tpos[0]; memset(ch[cp], 0, sizeof ch[cp]); for (int i = 1; i <= m; i ++) tpos[i] = insert(tpos[0], tpos[i - 1], t[i] - 'a'); std::fill(vis + tpos[0], vis + cp + 1, 0);
ll ans = 0; for (int i = 1, u = 1, le = 0; i <= m; i ++) { int x = t[i] - 'a'; while (u and !ch[u][x]) u = fa[u], le = len[u]; if (u) u = ch[u][x], ++ le; else u = 1; int R = query(seg[u], 1, n, l, r); while (!R or R - l + 1 <= len[fa[u]]) u = fa[u], le = len[u], R = query(seg[u], 1, n, l, r); le = R ? std::min(le, R - l + 1) : 0; int v = tpos[i], vlen = len[v], flen = vlen; while (!vis[v]) vis[v] = 1, v = fa[v], flen = len[v]; ans += vlen - std::max(flen, le); } printf("%lld\n", ans); } }
屠龙勇士
注意到每条龙使用的剑是完全确定的,所有限制都是同余方程,直接
exCRT/exgcd ,但是会爆 long long
,需要非常注意,在特定地方使用快速乘。
intmain(){ #ifndef LOCAL freopen("dragon.in", "r", stdin); freopen("dragon.out", "w", stdout); #endif
int T = read; while (T --) { int n = read, s = read; for (int i = 1; i <= n; i ++) read(a[i]); for (int i = 1; i <= n; i ++) read(p[i]); for (int i = 1; i <= n; i ++) read(aw[i]); std::multiset<ll> set; while (s --) set.insert(read);
ll min = 0, B = 0, M = 1; for (int i = 1; i <= n; i ++) { auto it = set.upper_bound(a[i]); if (it != set.begin()) -- it; int t = int(*it); set.erase(it); set.insert(aw[i]);
if (!p[i]) return0; ll x, y, g = exgcd(t, p[i], x, y); if (a[i] % g) goto fail; ll m = p[i] / g, b = mul(x, a[i] % p[i] / g, m); if (b < 0) b += m;
g = exgcd(m, M, x, y); ll d = B - b; if (d % g) goto fail; d /= g; M *= m / g; B = (b + mul(mul(x, m, M), d, M)) % M; if (B < 0) B += M;
min = std::max(min, (a[i] + t - 1) / t); }
if (B < min) { ll d = (min - B + M - 1) / M; B += d * M; } printf("%lld\n", B);
continue; fail: puts("-1"); } }
情报中心
观察了下数据表,意识到这题要拿部分分必须从特殊性质下手。
暴力直接 \(O(n^3)\)
该咋枚举咋枚举,15 分。
链的话可以正反来两次扫描线,由于每条边都是非负权值,算入一个的少了边的方案不会影响答案,15
分。
\(c_i=0\)
就只要考虑路径的代价,枚举每一条边,用 set
启发式合并求出经过每条边最小的两条路径,15 分。
namespace FORCE { constint maxn = 305; std::bitset<maxn> bs[maxn], bm[maxn]; ll main(int n, int m){ for (int u = 2; u <= n; u ++) { bs[u] = bs[fa[u]]; bs[u].set(si(u)); } for (int i = 1; i <= m; i ++) bm[i] = bs[ma[i]] ^ bs[mb[i]]; ll ans = -inf; for (int i = 1; i <= m; i ++) for (int j = 1; j < i; j ++) { if ((bm[i] & bm[j]).any()) { std::bitset<maxn> b = bm[i] | bm[j]; ll now = - mc[i] - mc[j]; for (int k = 1; k <= n; k ++) if (b.test(si(k))) now += fw[k]; ans = std::max(ans, now); } } return ans; } };
namespace CHAIN { std::vector<int> ve[maxn]; ll s[maxn]; ll bit[maxn]; voidmodify(int p, int n, ll x){ for (int k = p; k <= n; k += k & -k) bit[k] = std::max(bit[k], x); } ll query(int p){ ll res = -inf-inf; for (int k = p; k; k -= k & -k) res = std::max(res, bit[k]); return res; } ll main(int n, int m){ for (int i = 2; i <= n; i ++) s[i] = s[i - 1] + fw[i]; for (int i = 1; i <= n; i ++) ve[i].clear(); for (int i = 1; i <= m; i ++) { if (ma[i] > mb[i]) std::swap(ma[i], mb[i]); /* mc[i] += s[mb[i]] - s[ma[i]]; */ ve[mb[i]].push_back(i); } for (int R = 1; R <= n; R ++) std::sort(ve[R].begin(), ve[R].end(), [] (int i, int j) { return ma[i] > ma[j]; }); std::fill(bit, bit + n + 1, -inf-inf); ll ans = -inf; for (int R = 1; R <= n; R ++) for (int i : ve[R]) { ans = std::max(ans, -mc[i] + s[mb[i]] - s[ma[i]] + query(n - ma[i])); modify(n - ma[i], n, -mc[i]); } std::fill(bit, bit + n + 1, -inf-inf); for (int R = n; R; R --) for (int i : ve[R]) { ans = std::max(ans, -mc[i] - s[ma[i]] + query(mb[i] - 1)); modify(ma[i], n, -mc[i] + s[mb[i]]); } return ans; } };
namespace C0 { constint maxk = 20, Maxk = 18; std::multiset<ll> a[maxn], b[maxn]; int fa[maxk][maxn], deep[maxn]; intlca(int x, int y){ if (deep[x] < deep[y]) std::swap(x, y); for (int k = Maxk - 1; k >= 0; k --) if (deep[fa[k][x]] >= deep[y]) x = fa[k][x]; if (x == y) return x; for (int k = Maxk - 1; k >= 0; k --) if (fa[k][x] != fa[k][y]) x = fa[k][x], y = fa[k][y]; return ::fa[x]; } ll main(int n, int m){ for (int u = 1; u <= n; u ++) { deep[u] = deep[::fa[u]] + 1; fa[0][u] = ::fa[u]; for (int k = 1; k < Maxk; k ++) fa[k][u] = fa[k - 1][fa[k - 1][u]]; } for (int u = n; u; u --) a[u].clear(), b[u].clear(); for (int i = 1; i <= m; i ++) { a[ma[i]].insert(mc[i]); a[mb[i]].insert(mc[i]); int c = lca(ma[i], mb[i]); b[c].insert(mc[i]); b[c].insert(mc[i]); } ll ans = inf; for (int u = n; u; u --) { for (int v : G[u]) { if (a[v].size() > a[u].size()) std::swap(a[u], a[v]); for (ll x : a[v]) a[u].insert(x); } for (ll x : b[u]) a[u].erase(a[u].find(x)); if (a[u].size() >= 2) ans = std::min(ans, *a[u].begin() + *(++a[u].begin())); } return -ans; } };
intmain(){ int T = read; while (T --) { ++ Case; int n = read; for (int u = 1; u <= n; u ++) G[u].clear(); bool _chain = 1, _c0 = 1; for (int i = 1; i < n; i ++) { int a = read, b = read; G[fa[b] = a].push_back(b); read(fw[b]); _chain &= a == b - 1; _c0 &= fw[b] == 0; } int m = read; for (int i = 1; i <= m; i ++) { read(ma[i], mb[i], mc[i]); if (ma[i] == mb[i]) -- i, -- m; } ll ans; if (_chain) ans = CHAIN::main(n, m); elseif (_c0) ans = C0::main(n, m); else ans = FORCE::main(n, m); if (ans == -inf) puts("F"); elseprintf("%lld\n", ans); } }
voiddfs(int u){ if (G[u].empty()) return le[++ lp] = u, void(); std::sort(G[u].begin(), G[u].end()); for (int v : G[u]) dfs(v); }
ll ans = 0; voidforce(int u, int n){ if (n == 1) { for (int v : G[u]) if (v == 1) ++ ans; return; } vis[u] = 1; for (int v : G[u]) if (!vis[v]) force(v, n - 1); vis[u] = 0; }
intmain(){ #ifndef LOCAL freopen("polygon.in", "r", stdin); freopen("polygon.out", "w", stdout); #endif
int n = read, m = read; for (int u = 2; u <= n; u ++) G[fa[u] = read].push_back(u); dfs(1); for (int u = 2; u <= n; u ++) G[u].push_back(fa[u]); if (lp <= m * 2 + 1) { for (int i = 1; i <= lp; i ++) for (int j = 1; j <= lp; j ++) if (j != i) G[le[i]].push_back(le[j]); } else { for (int i = 1; i <= lp; i ++) le[lp + i] = le[i]; for (int i = 1; i <= lp; i ++) for (int j = i + 1; j <= i + m; j ++) { G[le[i]].push_back(le[j]); G[le[j]].push_back(le[i]); } } force(1, n); printf("%lld\n", ans >> 1); }
structroute {int s, t, p, q, id; }; structT {int x, y; }; T operator - (T a, T b) { return {a.x - b.x, a.y - b.y}; } ll cross(T a, T b){ return1ll * a.x * b.y - 1ll * a.y * b.x; }
structHull { std::vector<T> st; size_t b; staticintq(T p, int k){ return p.y - k * p.x; } intquery(int k){ if (b >= st.size()) return inf; while (b + 1 < st.size() andq(st[b + 1], k) <= q(st[b], k)) ++ b; returnq(st[b], k); } voidadd(T p){ auto sp = st.size(); if (sp and st[sp - 1].x == p.x and st[sp - 1].y < p.y) return; while (sp >= b + 2andcross(st[sp - 1] - st[sp - 2], p - st[sp - 1]) <= 0) st.pop_back(), -- sp; st.push_back(p), ++ sp; } };
std::vector<route> qu[maxt], ad[maxt]; int f[maxn]; Hull h[maxn];
intmain(){ #ifndef LOCAL freopen("route.in", "r", stdin); freopen("route.out", "w", stdout); #endif
int n = read, m = read, A = read, B = read, C = read; for (int i = 1; i <= m; i ++) { int s = read, t = read, p = read, q = read; qu[p].push_back({s, t, p, q, i}); ad[q].push_back({s, t, p, q, i}); f[i] = inf; }
int ans = inf; for (int t = 0; t <= Maxt; t ++) { for (route r : ad[t]) { if (r.s == 1) f[r.id] = A * r.p * r.p + B * r.p + C; if (f[r.id] < inf) h[r.t].add({2 * A * r.q, A * r.q * r.q - B * r.q + f[r.id]}); } for (route r : qu[t]) { f[r.id] = h[r.s].query(r.p); if (f[r.id] < inf) f[r.id] += A * r.p * r.p + B * r.p + C; if (r.t == n and f[r.id] < inf) ans = std::min(ans, f[r.id] + r.q); } }
voiddp(int n, int lim){ for (int i = 1; i <= n + 1; i ++) f[i][i - 1] = 1; for (int x = 1; x <= lim; x ++) { for (int l = 1; l <= n; l ++) { if (L[l] <= x and x <= R[l]) ++ f[l][l]; for (int r = l + 1; r <= n; r ++) { int lm = (l + r - 1) >> 1, rm = (l + r + 2) >> 1; for (int i = lm; i <= rm; i ++) if (L[i] <= x and x <= R[i]) (f[l][r] += f[l][i - 1] * f[i + 1][r]) %= mod; } } tmp[x] = f[1][n]; } }
ll lage(int n, int W){ ll res = 0; for (int i = 0; i <= n; i ++) { ll now = tmp[i]; for (int j = 0; j <= n; j ++) if (j != i) { (now *= mod + W - j) %= mod; (now *= power(mod + i - j, -1)) %= mod; } res += now; } return res % mod; }
intmain(){ #ifndef LOCAL freopen("robot.in", "r", stdin); freopen("robot.out", "w", stdout); #endif
int n = read, W = 1000000000, test = 1; for (int i = 1; i <= n; i ++) read(L[i], R[i]), test &= L[i] == 1and R[i] == W; if (test) dp(n, n), printf("%lld\n", lage(n, W)); else dp(n, 10000), printf("%lld\n", tmp[10000]); }
intmain(){ int T = read; while (T --) { int n = read, K = read, L = read; for (int i = 1; i <= n; i ++) read(p[i].first); for (int i = 1; i <= n; i ++) read(p[i].second); std::sort(p + 1, p + n + 1, std::greater<par>()); for (int i = 1; i <= n; i ++) { for (int j = 0; j <= i and j <= L; j ++) for (int k = 0; j + k <= i and k <= K - L; k ++) { int a = i + L - j <= K ? p[i].first : 0; f[i][j][k] = f[i - 1][j][k] + a; if (j) chkmax(f[i][j][k], f[i - 1][j - 1][k] + p[i].first + p[i].second); if (k) chkmax(f[i][j][k], f[i - 1][j][k - 1] + a + p[i].second); } } printf("%lld\n", f[n][L][K - L]); } }
constint maxn = 70005; structpath {int w, L[2], R[2]; }; structKDT { int lti, rti; int p[2], min[2], max[2]; } pool[maxn]; #define self pool[now] #define lt pool[self.lti] #define rt pool[self.rti] int tmp[maxn]; int dis[maxn << 1]; std::vector<path> G[maxn];
int cmp_d; boolcmp(int a, int b){ return pool[a].p[cmp_d] < pool[b].p[cmp_d]; }
intbuild(int l, int r, int d){ if (l > r) return0; int mid = (l + r) >> 1; cmp_d = d; // XXX: 卧槽,这都能忘? std::nth_element(tmp + l, tmp + mid, tmp + r + 1, cmp); int now = tmp[mid]; self.lti = build(l, mid - 1, d ^ 1); self.rti = build(mid + 1, r, d ^ 1); self.min[0] = std::min({self.p[0], lt.min[0], rt.min[0]}); self.max[0] = std::max({self.p[0], lt.max[0], rt.max[0]}); self.min[1] = std::min({self.p[1], lt.min[1], rt.min[1]}); self.max[1] = std::max({self.p[1], lt.max[1], rt.max[1]}); return now; }
std::priority_queue<par> q; int N, TOT; int L[2], R[2]; void _relax (int u, int di) { if (di < dis[u]) { dis[u] = di; q.push(par(-di, u)); } } voidrelax(int now, int di){ ++ TOT; if (R[0] < self.min[0] or L[0] > self.max[0] or R[1] < self.min[1] or L[1] > self.max[1]) return; if (L[0] <= self.min[0] and self.max[0] <= R[0] and L[1] <= self.min[1] and self.max[1] <= R[1]) return _relax(now, di); if (L[0] <= self.p[0] and self.p[0] <= R[0] and L[1] <= self.p[1] and self.p[1] <= R[1]) _relax(now + N, di); relax(self.lti, di); relax(self.rti, di); }
intmain(){ #ifndef LOCAL freopen("jump.in", "r", stdin); freopen("jump.out", "w", stdout); #endif
read(N); int M = read; pool[0].min[0] = read; pool[0].min[1] = read; pool[0].max[0] = 1; pool[0].max[1] = 1;
for (int now = 1; now <= N; now ++) { read(self.p[0], self.p[1]); tmp[now] = now; } for (int i = 1; i <= M; i ++) { int s = read, w = read, l = read, r = read, d = read, u = read; G[s].push_back({w, {l, d}, {r, u}}); }
int root = build(1, N, 0); std::fill(dis, dis + N + N + 1, 2000000000); q.push(par(dis[N + 1] = 0, N + 1)); while (!q.empty()) { int now = q.top().second, d = q.top().first; q.pop(); if (d > dis[now]) continue; if (now > N) { int u = now - N; for (path p : G[u]) { L[0] = p.L[0]; L[1] = p.L[1]; R[0] = p.R[0]; R[1] = p.R[1]; /* int bak = TOT; */ relax(root, dis[now] + p.w); /* debug("%d\n", TOT - bak); */ } } else { if (self.lti) _relax(self.lti, dis[now]); if (self.rti) _relax(self.rti, dis[now]); _relax(now + N, dis[now]); } }
for (int i = 2; i <= N; i ++) printf("%d\n", dis[N + i]); }
mat make(int x){ mat a; for (int i = 1; i <= x; i ++) for (int j = 1; j <= N; j ++) a.x[i][j] = C(j - 1, i - 1) * C(N - j, x - i) % mod * iC(N, x) % mod; for (int i = x + 1; i <= N; i ++) for (int j = 1; j <= N; j ++) a.x[i][j] = C(j - 1, i - x - 1) * C(N - j, N - i) % mod * iC(N, x) % mod; return a; }
intmain(){ #ifndef LOCAL freopen("landlords.in", "r", stdin); freopen("landlords.out", "w", stdout); #endif
read(N); int m = read, t = read; bool same = 1; for (int i = 1; i <= m; i ++) read(A[i]), same &= A[i] == A[1];
if (N > 100) return1;
fac[0] = 1; for (int i = 1; i <= N; i ++) fac[i] = fac[i - 1] * i % mod; ifac[N] = power(fac[N], -1); for (int i = N; i; i --) ifac[i - 1] = ifac[i] * i % mod;
mat P; for (int i = 1; i <= N; i ++) for (int j = 1; j <= N; j ++) P.x[i][j] = i == j;
if (same) { mat B = make(A[1]); while (m) { if (m & 1) P *= B; B *= B; m >>= 1; } } else for (int i = 1; i <= m; i ++) P *= make(A[i]);
for (int i = 1; i <= N; i ++) for (int j = 1; j <= N; j ++) (ans[j] += P.x[i][j] * ll(t == 1 ? i : i * i)) %= mod;
int q = read; while (q --) printf("%lld\n", ans[int(read)]); }
intmain(){ #ifndef LOCAL freopen("landlords.in", "r", stdin); freopen("landlords.out", "w", stdout); #endif
read(N); int m = read, t = read; bool same = 1; for (int i = 1; i <= m; i ++) read(A[i]), same &= A[i] == A[1];
fac[0] = 1; for (int i = 1; i <= N; i ++) fac[i] = fac[i - 1] * i % mod; ifac[N] = power(fac[N], -1); for (int i = N; i; i --) ifac[i - 1] = ifac[i] * i % mod; ll coe = 1;
ll d = 1; for (int i = 1; i <= m; i ++) { (d *= C(N - 2, A[i]) + C(N - 2, A[i] - 2)) %= mod; (d *= iC(N, A[i])) %= mod; } ll rem = 1ll * N * (N + 1) / 2; for (int i = 1; i <= N; i ++) ans[i] = i * d % mod, rem += mod - ans[i]; rem = rem % mod * power(N, -1) % mod; for (int i = 1; i <= N; i ++) (ans[i] += rem) %= mod;
int q = read; while (q --) printf("%lld\n", ans[int(read)] * coe % mod); }
namespace FORCE { constint maxn = 500; bool las[maxn]; bool link[maxn][maxn]; voidmain(int n, int){ for (int i = 0; i < n - 1; i ++) { modify(i); for (int j = 0; j <= i; j ++) if (link[j][i] or j == i) las[j] ^= 1; for (int j = i + 1; j < n; j ++) { bool now = query(j); if (now != las[j]) link[i][j] = 1, report(i, j); las[j] = now; } } } };
namespace MATCH { int match[maxn]; voidmain(int n, int){ for (int k = 0; (1 << k) < n; k ++) { for (int i = 0; i < n; i ++) if (i >> k & 1) modify(i); for (int i = 0; i < n; i ++) if (query(i) != (i >> k & 1)) match[i] |= 1 << k; for (int i = 0; i < n; i ++) if (i >> k & 1) modify(i); } for (int i = 0; i < n; i ++) if (i < match[i]) report(i, match[i]); } };
voidexplore(int n, int m){ if (n % 10 == 8) MATCH::main(n, m); else FORCE::main(n, m); }
B
部分那个感觉可以来个二分什么的,因为对一个前缀进行修改操作,就可以直到一个后缀的父亲是否在这段前缀里头。