[bzoj3162]独钓寒江雪_树hash_树形dp
独钓寒江雪
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3162
题解:
首先,如果没有那个本质相同的限制这就是个傻逼题。
直接树形dp就好。
那么如果加上那个限制呢?
我们发现,无论最后怎么本质相同,树的重心一定不变。
故此,从重心开始去重即可。
参考:https://www.cnblogs.com/zhoushuyu/p/9295759.html
代码:
#include <bits/stdc++.h> #define N 500010 using namespace std; const int mod = 1000000007 ; char *p1, *p2, buf[100000]; typedef unsigned long long ll; ll bs1 = 20021214 ; ll bs2 = 20030315 ; #define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ ) int rd() { int x = 0; char c = nc(); while (c < 48) { c = nc(); } while (c > 47) { x = (((x << 2) + x) << 1) + (c ^ 48), c = nc(); } return x; } int n, inv[N], to[N << 1], nxt[N << 1], head[N], tot, sz[N], w[N], root, rt1, rt2, flag, f[2][N], tmp[N]; ll hs[N]; inline void add(int x, int y) { to[ ++ tot] = y; nxt[tot] = head[x]; head[x] = tot; } void getroot(int p, int fa) { sz[p] = 1; w[p] = 0; for (int i = head[p]; i; i = nxt[i]) { if(to[i] != fa) { getroot(to[i], p); sz[p] += sz[to[i]]; w[p] = max(w[p], sz[to[i]]); } } w[p] = max(w[p], n - sz[p]); if (w[p] < w[root]) { root = p; } } int C(int n, int m) { int re = 1; for (int i = n - m + 1; i <= n; i ++ ) { re = (ll)re * i % mod; } for (int i = 1; i <= m; i ++ ) { re = (ll)re * inv[i] % mod; } return re; } inline bool cmp(int i, int j) { return hs[i] < hs[j]; } void dfs(int p, int fa) { sz[p] = f[0][p] = f[1][p] = 1; for (int i = head[p]; i; i = nxt[i]) { if (to[i] != fa) { dfs(to[i], p); sz[p] += sz[to[i]]; } } int len = 0; for (int i = head[p]; i; i = nxt[i]) { if (to[i] != fa) { tmp[ ++ len] = to[i]; } } sort(tmp + 1, tmp + len + 1, cmp); for (int i = 1, j = 1; i <= len; i = j) { while (j <= len && hs[tmp[j]] == hs[tmp[i]]) { j ++ ; } f[0][p] = (ll)f[0][p] * C(f[0][tmp[i]] + f[1][tmp[i]] + j - i - 1, j - i) % mod; f[1][p] = (ll)f[1][p] * C(f[0][tmp[i]] + j - i - 1, j - i) % mod; } hs[p] = bs2 * len + sz[p]; for (int i = 1; i <= len; i ++ ) { hs[p] = (hs[p] * bs1) ^ hs[tmp[i]]; } } int main() { n = rd(); inv[0] = inv[1] = 1; for (int i = 2; i <= n; i ++ ) { inv[i] = (ll)inv[mod % i] * (mod - mod / i) % mod; } for (int i = 1; i < n; i ++ ) { int x = rd(), y = rd(); add(x, y), add(y, x); } w[0] = n; getroot(1, 0); getroot(root, 0); for (int i = head[root], last = 0; i; last = i, i = nxt[i]) { if (sz[to[i]] * 2 == n) { n ++ ; if (i == head[root]) { head[root] = nxt[i]; } else { nxt[last] = nxt[i]; } for (int j = head[to[i]], lst = 0; j; lst = j, j = nxt[j]) { if (to[j] == root) { if (j == head[to[i]]) { head[to[i]] = nxt[j]; } else { nxt[lst] = nxt[j]; } break; } } add(n, root); add(root, n); add(n, to[i]); add(to[i], n); rt1 = root; rt2 = to[i]; root = n; flag = 1; break; } } dfs(root, 0); if (!flag) { cout << (f[0][root] + f[1][root]) % mod << endl ; } else if (hs[rt1] == hs[rt2]) { cout << (f[0][root] - C(f[1][rt1] + 1, 2) + mod) % mod; } else { cout << ((ll)f[0][rt1] * f[0][rt2] + (ll)f[0][rt1] * f[1][rt2] + (ll)f[1][rt1] * f[0][rt2]) % mod << endl ; } }
小结:树hash的时候,如果一个模数担心过不去,像我一样开两个就好了233
| 欢迎来原网站坐坐! >原文链接<