2020 ccpc 威海
阿新 • • 發佈:2020-11-04
2020 ccpc 威海
G Caesar Cipher
題意:
給你n個數, 你有兩種操作
1.將區間 \([l, r]\)的數加1, 同時在模上65536
2.詢問 \([l, l + x], [r, r + x]\) 問這兩段區間是否一樣
判斷兩個區間是否一樣?很容易想到雜湊, 對於操作如果直接取模那麼就很有可能出現hash衝突, 但是如果維護一個最大值, 然後暴力修改, 然後hash值取模改成1e9 + 7就可以a了
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 5e5 + 100; struct segment { ll sum, ha, maxn; }tree[40 * N]; ll fn[N], a[N], flag[40 * N]; const ll mod = 1e9 + 7; #define m (l + r) / 2 #define lson 2 * node #define rson 2 * node + 1 void build(int l, int r, int node) { if (l == r) { tree[node].sum = fn[l]; tree[node].ha = fn[l] * a[l]; tree[node].maxn = a[l]; return; } build(l, m, lson); build(m + 1, r, rson); tree[node].sum = tree[lson].sum + tree[rson].sum; tree[node].maxn = max(tree[lson].maxn, tree[rson].maxn); tree[node].ha = (tree[lson].ha + tree[rson].ha) % mod; } void push_down(int node) { if (flag[node]) { tree[lson].maxn += flag[node]; tree[rson].maxn += flag[node]; tree[lson].ha = (tree[lson].ha + (flag[node] % mod * tree[lson].sum % mod) % mod) % mod; tree[rson].ha = (tree[rson].ha + (flag[node] % mod * tree[rson].sum % mod) % mod) % mod; flag[lson] += flag[node]; flag[rson] += flag[node]; flag[node] = 0; } } void work(int l, int r, int node) { if (l == r) { tree[node].maxn = tree[node].maxn % 65536; tree[node].ha = tree[node].maxn * tree[node].sum % mod; return; } push_down(node); if (tree[lson].maxn >= 65536) { work(l, m, lson); } if (tree[rson].maxn >= 65536) { work(m + 1, r, rson); } tree[node].maxn = max(tree[lson].maxn, tree[rson].maxn); tree[node].ha = (tree[lson].ha + tree[rson].ha) % mod; } void update(int ql, int qr, int l, int r, int node) { if (ql <= l && qr >= r) { tree[node].maxn++; tree[node].ha = (tree[node].ha + tree[node].sum) % mod; flag[node]++; if (tree[node].maxn >= 65536) { push_down(node); work(l, r, node); } return; } push_down(node); if (ql <= m) update(ql, qr, l, m, lson); if (qr > m) update(ql, qr, m + 1, r, rson); tree[node].maxn = max(tree[lson].maxn, tree[rson].maxn); tree[node].ha = (tree[lson].ha + tree[rson].ha) % mod; } ll query(int ql, int qr, int l, int r, int node) { if (ql <= l && qr >= r) { return tree[node].ha; } ll ans = 0; push_down(node); if (ql <= m) ans = (ans + query(ql, qr, l, m, lson)) % mod; if (qr > m) ans = (ans + query(ql, qr, m + 1, r, rson)) % mod; return ans; } int main() { int n, q; scanf("%d %d", &n, &q); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); } fn[1] = 1; for (int i = 2; i <= n + 10; i++) { fn[i] = fn[i - 1] * 27; fn[i] %= mod; } build(1, n, 1); while (q--) { int op, l, r; scanf("%d %d %d", &op, &l, &r); if (op == 1) { update(l, r, 1, n, 1); } else { int x; scanf("%d", &x); ll ha = query(l, l + x - 1, 1, n, 1); ll ha1 = query(r, r + x - 1, 1, n, 1); if (l > r) { int len = l - r; ha1 = ha1 * fn[len + 1] % mod; } else { int len = r - l; ha = ha * fn[len + 1] % mod; } if (ha == ha1) { puts("yes"); } else { puts("no"); } } } }
C Rencontre
題意:
給你一顆樹, 然後有三個人每個選擇m個點最後問這三個到達某個點最短的期望是多少?
題解:
這題有個東西要知道, 假設樹上有三個點 \(a,b, c\)那麼這三個點到某點的最近距離是 \(\frac{1}{2}(dist(a, b) + dist(b, c) + dist(a, c))\) 如果你知道這個公式那麼答案不就是求
\(ans = \frac{\sum_{i\in{a}} \sum_{j\in{b}} \sum_{z\in{c}} dist(i, j) + dist(j, z)+ dist(i, z)}{2}\)
最後的期望就等於 \(\frac{ans}{cnta * cntb * cntc}\)
等於上面的公式可以在繼續化簡得到
\((\sum_{i\in{a}} \sum_{j\in{c}} dist(i, j) ) * cntc + (\sum_{i\in{a}} \sum_{j\in c} dist(i, j)) * cntb + (\sum_{i\in{b}} \sum_{j\in{c}} dist(i, j) ) * cnta\)
知道這個公式後就可以用dp求出 所有a到b的距離和, 所有a到c的距離和, 所有b到c的距離後。
注意爆long long
程式碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5 + 7; ll dp[N][3], sz[N][3]; int head[N], top = 1, n, a[N], b[N], c[N], visa[N], visb[N], visc[N]; struct edge { int to, w, nxt; }e[2 * N]; void add_edge(int u, int v, int w) { e[top].to = v; e[top].w = w; e[top].nxt = head[u]; head[u] = top++; } __int128 ab = 0, ac = 0, bc = 0; ll ma, mb, mc, sum; void dfs(int u, int fa) { if (visa[u]) { sz[u][0] = 1; } if (visb[u]) { sz[u][1] = 1; } if (visc[u]) { sz[u][2] = 1; } for (int i = head[u]; i; i = e[i].nxt) { int to = e[i].to; int w = e[i].w; if (to == fa) { continue; } dfs(to, u); dp[u][0] += dp[to][0] + sz[to][0] * 1ll * w; dp[u][1] += dp[to][1] + sz[to][1] * 1ll * w; dp[u][2] += dp[to][2] + sz[to][2] * 1ll * w; sz[u][0] += sz[to][0]; sz[u][1] += sz[to][1]; sz[u][2] += sz[to][2]; } } ll fn[N][3], fz[N][3]; void dfs1(int u, int fa) { if (visa[u]) { ac += fn[u][2]; ab += fn[u][1]; } if (visb[u]) { bc += fn[u][2]; } for (int i = head[u]; i; i = e[i].nxt) { int to = e[i].to; int w = e[i].w; if (to == fa) continue; ll sb = fn[u][1] - dp[to][1] - 1ll* w * sz[to][1]; sb = sb + w * (mb - sz[to][1]); fn[to][1] = sb + dp[to][1]; ll sc = fn[u][2] - dp[to][2] - 1ll * w * sz[to][2]; sc = sc + w * (mc - sz[to][2]); fn[to][2] = sc + dp[to][2]; dfs1(to, u); } } int main() { scanf("%d", &n); for (int i = 1; i < n; i++) { int u, v, w; scanf("%d %d %d", &u, &v, &w); add_edge(u, v, w); add_edge(v, u, w); } scanf("%d", &ma); for (int i = 1; i <= ma; i++) { scanf("%d", &a[i]); visa[a[i]] = 1; } scanf("%d", &mb); for (int i = 1; i <= mb; i++) { scanf("%d", &b[i]); visb[b[i]] = 1; } scanf("%d", &mc); for (int i = 1; i <= mc; i++) { scanf("%d", &c[i]); visc[c[i]] = 1; } sum = ma * mb * mc; dfs(1, 0); fn[1][0] = dp[1][0]; fn[1][1] = dp[1][1]; fn[1][2] = dp[1][2]; dfs1(1, 0); __int128 ans = ac * mb + bc * ma + ab * mc; ans = ans / 2; double res = (double)ans / (double)sum; printf("%.9f\n", res); }