P9663 Permutation on Tree 题解
考虑枚举一个 ,将 的看作 , 的看作 ,那么一个排列的贡献实际上就是 。
那么问题转变为一个给定一棵树,每一个点有权值 或 ,求所有排布方案的贡献之和。
设 表示 子树内的排布方案树之和是多少。
设 表示 子树内所有排布方案中第 个数是 还是 的排布方案有多少。
设 表示 子树内所有排布方案中第 个数和第 个数不同的方案数有多少。
在枚举一个 的情况时,贡献就是 。
转移方程建议自己手推。容易发现复杂度为 。
//code by Emissary #include<bits/stdc++.h> #define ll long long using namespace std; const int MAXN = 202; const int mod = 1e9+7; int n, r, siz[MAXN]; int val[MAXN], fac[MAXN<<1], ifac[MAXN<<1]; int head[MAXN], ne[MAXN<<1], to[MAXN<<1], cnt; int f[MAXN], g[MAXN][MAXN][2], h[MAXN][MAXN], o[MAXN][MAXN][2], q[MAXN][MAXN]; inline void add(int x, int y){++cnt;to[cnt]=y;ne[cnt]=head[x];head[x]=cnt;} inline int C(int x, int y){return x<y?0:1ll*fac[x]*ifac[y]%mod*ifac[x-y]%mod;} inline ll Quickpow(ll x, ll y){ ll z=1; while(y){ if(y&1) z=z*x%mod; x=x*x%mod; y>>=1; } return z; } inline void dfs(int x, int fa){ siz[x]=1; int lim; g[x][1][val[x]]=1; f[x]=1; for(int i=head[x];i;i=ne[i]){ if(to[i]==fa) continue; dfs(to[i],x); for(int j=0;j<=siz[x];++j) q[x][j]=h[x][j], h[x][j]=0; for(int j=2;j<=siz[x];++j) for(int k=1;k<=siz[to[i]];++k) (h[x][j+k-1]+=2ll*(1ll*g[to[i]][k][1]*g[x][j][0]%mod+1ll*g[to[i]][k][0]*g[x][j][1]%mod)%mod*C(j+k-3,j-2)%mod*C(siz[x]-j+siz[to[i]]-k,siz[x]-j)%mod)%=mod; (h[x][1]+=1ll*(1ll*g[to[i]][1][1]*g[x][1][0]%mod+1ll*g[to[i]][1][0]*g[x][1][1]%mod)*C(siz[x]-1+siz[to[i]]-1,siz[x]-1)%mod)%=mod; for(int j=2;j<siz[x];++j) for(int k=0;k<=siz[to[i]];++k) (h[x][j+k]+=1ll*q[x][j]*f[to[i]]%mod*C(j+k-2,k)%mod*C(siz[x]-j-1+siz[to[i]]-k,siz[to[i]]-k)%mod)%=mod; for(int k=1;k<siz[to[i]];++k) for(int j=1;j<=siz[x];++j) (h[x][j+k]+=1ll*h[to[i]][k]*f[x]%mod*C(j+k-2,j-1)%mod*C(siz[to[i]]-k-1+siz[x]-j,siz[x]-j)%mod)%=mod; for(int j=0;j<=siz[x];++j) o[x][j][0]=g[x][j][0], o[x][j][1]=g[x][j][1], g[x][j][0]=g[x][j][1]=0; for(int j=2;j<=siz[x];++j){ for(int k=0;k<=siz[to[i]];++k){ (g[x][j+k][0]+=1ll*o[x][j][0]*f[to[i]]%mod*C(j+k-2,k)%mod*C(siz[x]-j+siz[to[i]]-k,siz[x]-j)%mod)%=mod; (g[x][j+k][1]+=1ll*o[x][j][1]*f[to[i]]%mod*C(j+k-2,k)%mod*C(siz[x]-j+siz[to[i]]-k,siz[x]-j)%mod)%=mod; } } for(int k=1;k<=siz[to[i]];++k){ for(int j=1;j<=siz[x];++j){ (g[x][j+k][0]+=1ll*g[to[i]][k][0]*f[x]%mod*C(j+k-2,j-1)%mod*C(siz[to[i]]-k+siz[x]-j,siz[x]-j)%mod)%=mod; (g[x][j+k][1]+=1ll*g[to[i]][k][1]*f[x]%mod*C(j+k-2,j-1)%mod*C(siz[to[i]]-k+siz[x]-j,siz[x]-j)%mod)%=mod; } } f[x]=1ll*f[x]*f[to[i]]%mod*C(siz[x]+siz[to[i]]-1,siz[to[i]])%mod; g[x][1][val[x]]=f[x]; if(siz[x]>1) (h[x][1]+=1ll*q[x][1]*C(siz[x]+siz[to[i]]-2,siz[x]-2)%mod*f[to[i]]%mod)%=mod; siz[x]+=siz[to[i]]; } return ; } inline void prework(int lim){ fac[0]=ifac[0]=1; for(int i=1;i<=lim;++i) fac[i]=1ll*fac[i-1]*i%mod, ifac[i]=Quickpow(fac[i],mod-2); return ; } inline void clear(){ memset(f,0,sizeof f); memset(g,0,sizeof g); memset(h,0,sizeof h); return ; } int main(){ cin >> n >> r; prework(n<<1); for(int i=2;i<=n;++i){ int x, y; cin >> x >> y; add(x,y), add(y,x); } int ans=0; for(int x=1;x<n;++x){ for(int i=1;i<=n;++i) val[i]=(i>x); clear(); dfs(r,0); for(int i=1;i<n;++i) (ans+=h[r][i])%=mod; } cout << ans; return 0; }
本文作者:OI 生活
本文链接:https://www.cnblogs.com/OccasionalDreamer/p/18012090
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
标签:
动态规划
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步