题目大意:
给你一棵n个结点的树,求有多少种染色方案,使得染色过程中染过色的结点始终连成一块。
思路:
树形DP。
设f[x]表示先放x时,x的子树中的染色方案数,y为x的子结点。
则f[x]=prod{f[y]}*(size[x]-1)!/prod{size[y]}。
现在我们改变f[x]的含义,让其表示先放x时,整棵子树的方案数。
考虑根的转移对答案做出的贡献。
假设我们从x转移到y,那么就要把y从x中剔除,
设剔除y后的f[x]为t,则t=f[x]*size[y]*(size[x]-1-size[y])!/f[y]/(size[x]-1)!。
这是我们要把x子树中的方案数,也就是t算入f[y]中。
f[y]=f[y]*t*(n-1)!/(size[y]-1)!/(n-1-size[y])!。
把t代入,发现f[y]=f[x]*(n-1-size[y])!*size[y]!/(size[y]-1)!/(n-size[y])!。
时间复杂度O(n)。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 typedef long long int64; 5 inline int getint() { 6 register char ch; 7 while(!isdigit(ch=getchar())); 8 register int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int N=100001; 13 const int mod=1e9+7; 14 std::vector<int> e[N]; 15 inline void add_edge(const int &u,const int &v) { 16 e[u].push_back(v); 17 e[v].push_back(u); 18 } 19 void exgcd(const int &a,const int &b,int &x,int &y) { 20 if(!b) { 21 x=1; 22 y=0; 23 return; 24 } 25 exgcd(b,a%b,y,x); 26 y-=a/b*x; 27 } 28 inline int inv(const int &x) { 29 int ret,tmp; 30 exgcd(x,mod,ret,tmp); 31 return (ret%mod+mod)%mod; 32 } 33 int f[N],fact[N],size[N]; 34 void dfs(const int &x,const int &par) { 35 f[x]=size[x]=1; 36 for(unsigned i=0;i<e[x].size();i++) { 37 const int &y=e[x][i]; 38 if(y==par) continue; 39 dfs(y,x); 40 size[x]+=size[y]; 41 f[x]=(int64)f[x]*f[y]%mod*inv(fact[size[y]])%mod; 42 } 43 f[x]=(int64)f[x]*fact[size[x]-1]%mod; 44 } 45 void move(const int &x,const int &par) { 46 for(unsigned i=0;i<e[x].size();i++) { 47 const int &y=e[x][i]; 48 if(y==par) continue; 49 f[y]=(int64)f[x]*fact[size[1]-1-size[y]]%mod*fact[size[y]]%mod*inv(fact[size[y]-1])%mod*inv(fact[size[1]-size[y]])%mod; 50 move(y,x); 51 } 52 } 53 int main() { 54 const int n=getint(); 55 fact[0]=1; 56 for(register int i=1;i<n;i++) { 57 fact[i]=(int64)fact[i-1]*i%mod; 58 } 59 for(register int i=1;i<n;i++) { 60 add_edge(getint(),getint()); 61 } 62 int ans=0; 63 dfs(1,0); 64 move(1,0); 65 for(register int i=1;i<=n;i++) { 66 ans=(ans+f[i])%mod; 67 } 68 printf("%d ",ans); 69 return 0; 70 }