NOIP 模擬 $98\; \rm 構樹$
阿新 • • 發佈:2021-11-14
題解
題解 \(by\;zj\varphi\)
根據擴充套件凱利定理,一個被固定了一些邊的生成樹,被這些邊分成了 \(m\) 個聯通塊,每個聯通塊大小為 \(siz_i\)
那麼其形態的個數為 \(n^{m-2}\Pi_{i=1}^msiz_i\)
這道題裡為了簡化,強制以 \(1\) 為根,因為以誰為根不對問題造成影響。
設 \(dp_{i,j,k}\) 表示在以 \(i\) 為根的聯通塊中,大小為 \(j\) ,匹配了 \(k\) 條邊的方案數。
轉移方程就是:
\[dp_{x,j,k}\times dp_{v,s,l}\rightarrow dp_{x,j+s,k+l+1}\\ ns\times dp_{x,j,k}\times dp_{v,s,l}\rightarrow dp_{x,j,k+l}\\ -dp_{x,j,k}\times dp_{v,s,l}\rightarrow dp_{x,j+s,k+l} \]最後一個意思可以理解為 不合法的情況=總情況-合法的情況,求解不合法的情況。
發現大小這一位可以理解為在當前聯通塊選一個點,所以可以省去。
Code
#include<bits/stdc++.h> #define ri signed #define pd(i) ++i #define bq(i) --i #define func(x) std::function<x> namespace IO{ char buf[1<<21],*p1=buf,*p2=buf; #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++ #define dg1(x) std::cerr << #x"=" << x << ' ' #define dg2(x) std::cerr << #x"=" << x << std::endl #define Dg(x) assert(x) struct nanfeng_stream{ template<typename T>inline nanfeng_stream &operator>>(T &x) { bool f=false;x=0;char ch=gc(); while(!isdigit(ch)) f|=ch=='-',ch=gc(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=gc(); return x=f?-x:x,*this; } }cin; } using IO::cin; namespace nanfeng{ #define FI FILE *IN #define FO FILE *OUT template<typename T>inline T cmax(T x,T y) {return x>y?x:y;} template<typename T>inline T cmin(T x,T y) {return x>y?y:x;} static const int N=8003,MOD=1e9+7; struct edge{int v,nxt;}e[N<<1]; int dp[N][N][2],tmp[N][2],first[N],siz[N],t=1,n,u,v; auto add=[](int u,int v) { e[t]={v,first[u]},first[u]=t++; e[t]={u,first[v]},first[v]=t++; }; void dfs(int x,int fa) { siz[x]=dp[x][0][0]=dp[x][0][1]=1; for (ri i(first[x]),v;i;i=e[i].nxt) { if ((v=e[i].v)==fa) continue; dfs(v,x); for (ri l(0);l<siz[x];pd(l)) for (ri k(0);k<siz[v];pd(k)) { int x0=dp[x][l][0],x1=dp[x][l][1],v0=dp[v][k][0],v1=dp[v][k][1]; tmp[l+k+1][0]+=1ll*x0*v0%MOD; if (tmp[l+k+1][0]>=MOD) tmp[l+k+1][0]-=MOD; tmp[l+k+1][1]+=(1ll*x0*v1+1ll*x1*v0)%MOD; if (tmp[l+k+1][1]>=MOD) tmp[l+k+1][1]-=MOD; tmp[l+k][0]+=1ll*x0*v1%MOD*n%MOD; tmp[l+k][1]+=1ll*x1*v1%MOD*n%MOD; if (tmp[l+k][0]>=MOD) tmp[l+k][0]-=MOD; if (tmp[l+k][1]>=MOD) tmp[l+k][1]-=MOD; tmp[l+k][0]-=1ll*x0*v0%MOD; tmp[l+k][1]-=(1ll*x0*v1+1ll*x1*v0)%MOD; if (tmp[l+k][0]<0) tmp[l+k][0]+=MOD; if (tmp[l+k][1]<0) tmp[l+k][1]+=MOD; } siz[x]+=siz[v]; for (ri s(0);s<siz[x];pd(s)) for (ri k(0);k<2;pd(k)) dp[x][s][k]=tmp[s][k],tmp[s][k]=0; } } auto fpow=[](int x,int y) { int res=1; while(y) { if (y&1) res=1ll*res*x%MOD; x=1ll*x*x%MOD; y>>=1; } return res; }; inline int main() { FI=freopen("tree.in","r",stdin); FO=freopen("tree.out","w",stdout); cin >> n; for (ri i(1);i<n;pd(i)) cin >> u >> v,add(u,v); dfs(1,0); for (ri i(0);i<n;pd(i)) { long long tmp=1ll*dp[1][i][1]*fpow(n,MOD-2)%MOD; printf("%lld ",tmp%MOD); } return 0; } } int main() {return nanfeng::main();}