考虑枚举一个 \(x \in [1,n)\),将 \(\leq x\) 的看作 \(0\),\(>x\) 的看作 \(1\),那么一个排列的贡献实际上就是 \(\sum _{x=1}^{n-1}\sum [[p_i\leq x]+ [p_{i+1}>x]=1]\)。
那么问题转变为一个给定一棵树,每一个点有权值 \(0\) 或 \(1\),求所有排布方案的贡献之和。
设 \(f_x\) 表示 \(x\) 子树内的排布方案树之和是多少。
设 \(g_{x,k,0/1}\) 表示 \(x\) 子树内所有排布方案中第 \(k\) 个数是 \(0\) 还是 \(1\) 的排布方案有多少。
设 \(h_{x,k}\) 表示 \(x\) 子树内所有排布方案中第 \(k\) 个数和第 \(k+1\) 个数不同的方案数有多少。
在枚举一个 \(x\) 的情况时,贡献就是 \(\sum_{i=1}^{n-1} h_{r,i}\)。
转移方程建议自己手推。容易发现复杂度为 \(O(n^3)\)。
//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;
}
标签:siz,P9663,int,题解,Tree,dfs,MAXN,排布,mod
From: https://www.cnblogs.com/OccasionalDreamer/p/18012090