P9663 Permutation on Tree 题解

考虑枚举一个 \(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;
}
posted @ 2024-02-08 20:00  OccDreamer  阅读(37)  评论(0)    收藏  举报