【CF917D】Stranger Trees 樹形DP+Prufer序列
阿新 • • 發佈:2018-02-21
pri names brush 但是 連通 for limit limits cpp
【CF917D】Stranger Trees
題意:給你一棵n個點的樹,對於k=1...n,問你有多少有標號的n個點的樹,與給出的樹有恰好k條邊相同?
$n\le 100$
題解:我們先考慮容斥,求出和給出的樹至少有k個點相同的樹的數量。我們先選出原樹中的k條邊,然後剩下的邊隨便連。選出k條邊後,原樹被分成n-k個連通塊,設其大小分別為$siz_1,siz_2...siz_{n-k}$。那麽剩下的邊隨便連的方案數是多少呢?我們不妨把每個連通塊看成一個點,答案變成n個點的完全圖的生成樹個數,根據Prufer序列知道這個答案是$n^{n-2}$。但是這裏一個連通塊的大小並不是1。對於一個大小為$siz$的連通塊,如果它在Prufer序列中出現了j次,那麽它對答案的貢獻其實是$siz^{j+1}$(因為它的度數是j+1)。我們可以先把$\prod\limits_{i=1}^{n-k}siz_i$提出來,然後對於Prufer序列中的每個位置,如果它是第i個連通塊,則貢獻為$siz_i$,所以總的貢獻為$\sum\limits_{i=1}^{n-k}siz_i=n$,那麽答案就是$\prod\limits_{i=1}^{n-k}siz_i\times n^{n-k-2}$。
所以我們考慮樹形DP,用f[x][a][b]表示在x的子樹中,已經連了a條邊,包含x的連通塊大小為b的總貢獻。最後容斥一發即可。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; const ll P=1000000007; int n,m,cnt; int to[210],nxt[210],head[110],siz[110]; ll f[110][110][110],g[110][110],c[110][110],h[110],bt[110]; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘) f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } void dfs(int x,int fa) { f[x][1][0]=1,siz[x]=1; for(int i=head[x],j,k,a,b,y;i!=-1;i=nxt[i]) if(to[i]!=fa) { y=to[i],dfs(to[i],x); memset(g,0,sizeof(g)); for(j=1;j<=siz[x];j++) for(k=1;k<=siz[y];k++) { for(a=0;a<siz[x];a++) for(b=0;b<siz[y];b++) { g[j+k][a+b+1]=(g[j+k][a+b+1]+f[x][j][a]*f[y][k][b])%P; g[j][a+b]=(g[j][a+b]+f[x][j][a]*f[y][k][b]%P*k)%P; } } memcpy(f[x],g,sizeof(g)); siz[x]+=siz[y]; } } inline void add(int a,int b) { to[cnt]=b,nxt[cnt]=head[a],head[a]=cnt++; } int main() { n=rd(); int i,j,a,b; memset(head,-1,sizeof(head)); for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a); dfs(1,0); for(bt[0]=i=1;i<=n;i++) bt[i]=bt[i-1]*n%P; for(i=0;i<=n;i++) for(c[i][0]=j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%P; for(i=1;i<n;i++) for(j=0;j<n;j++) h[j]=(h[j]+f[1][i][j]*i)%P; h[n-1]=1; for(i=0;i<n-1;i++) h[i]=h[i]*bt[n-i-2]%P; for(i=n-1;i>=0;i--) { for(j=i+1;j<n;j++) h[i]=(h[i]-c[j][i]*h[j])%P; h[i]=(h[i]+P)%P; } for(i=0;i<n;i++) printf("%lld ",h[i]); return 0; }
【CF917D】Stranger Trees 樹形DP+Prufer序列