[bzoj3162]独钓寒江雪_树hash_树形dp
发布时间:2020-12-13 21:31:27 所属栏目:PHP教程 来源:网络整理
导读:独钓寒江雪 题目链接 :https://www.lydsy.com/JudgeOnline/problem.php?id=3162 题解 : 首先,如果没有那个本质相同的限制这就是个傻逼题。 直接树形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 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |