2 1 5 1 2 2 3
1 42HintIn the second sample, the 4 edges are (1,2),(2,3),(2,4),(3,5). All the connected sets are {1},{2},{3},{4},{5},{1,2},{2,3},{2,4},{3,5},{1,2,3},{1,2,4},{2,3,4},{2,3,5},{1,2,3,4},{1,2,3,5},{2,3,4,5},{1,2,3,4,5}. If you need a larger stack size, please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.
用f[i]表示包含i的连通块数量,g[i]表示以i为根节点的连通块的数量。
下面给出DP方程:
f[n]=f[n]*(g[son[n][i]]+1)%mod+g[n]*f[son[n][i]]%mod;
f[n]%=mod;
g[n]=g[n]*(g[son[n][i]]+1)%mod;
f[n]*(g[son[n][i]]+1):对于结点包含n的连通块数量f[n],当检测到新子结点时,自身大小要乘上以子结点为根的连通块数量,同时还要加上自身g[n]*f[son[n][i]]:子结点的连通块同样需要更新
g[n]=g[n]*(g[son[n][i]]+1):此处是对以n为根节点的连通块数量进行更新,每多一个子结点,之前的结果都要对该子树进行更新。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdlib> #include<stack> #include <queue> #include <set> #include <map> using namespace std; const int inf = 2147483647; const double PI = acos(-1.0); const double e = 2.718281828459; const int mod = 1000000007; typedef long long LL; #pragma comment(linker, "/STACK:102400000,102400000") //freopen("in.txt","r",stdin); //输入重定向,输入数据将从in.txt文件中读取 //freopen("out.txt","w",stdout); //输出重定向,输出数据将保存在out.txt文件中cin const int nmax = 200005; LL f[nmax], g[nmax]; vector<int>son[nmax]; int t; void dp_dfs(int x, int father) { for (int i = 0; i < son[x].size(); ++i) { if (son[x][i] != father) { dp_dfs(son[x][i], x); f[x] = (f[x] * g[son[x][i]] % mod + f[x] + g[x] * f[son[x][i]] % mod) % mod; g[x] = g[x] * (g[son[x][i]] + 1) % mod; } } } int main() { int i, j; int n; scanf("%d", &n); while (n--) { scanf("%d", &t); fill(f, f + t + 1, 1); fill(g, g + t + 1, 1); //cout << f[1] << endl; for (i = 2; i <= t; ++i) { int x; scanf("%d", &x); son[x].push_back(i); son[i].push_back(x); } dp_dfs(1, -1); LL ans = 0; for (i = 1; i <= t; ++i) { ans += f[i]; ans %= mod; son[i].clear(); } cout << ans << endl; } }