[ARC087F] Squirrel Migration

\(\mathcal {Link}\)

先考虑随便选一个点为根。

\[\sum_{i=1}^n dis(i,p_i)=\sum_{i=1}^n dep_i+dep_{p_i}-2\times dep_{\operatorname{lca}(i,p_i)}=2\times (\sum_{i=1}^n dep_i-\sum_{i=1}^n dep_{\operatorname{lca}(i,p_i)}) \]

显然,我们希望 \(\sum dep_{\operatorname{lca}(i,p_i)}\) 最小。

考虑到如果我们选择树的重心为根,存在一种排列使得所有 LCA 都为根节点。(因为没有绝对众数,可以调整法证明)

现在考虑如何求案数。

考虑设 \(f(i)\) 表示钦定了 \(i\) 个不符合条件的方案数。

\(g(i,j)\) 表示前 \(i\) 个子树钦定 \(j\) 个不合法,只考虑不合法位置所填数的方案数。这个可以直接树形背包合并。

\(f(i)=g(n,i)\times (n-i)!\)

答案可以容斥

\[\sum_{i=0}^n (-1)^i f(i) \]

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
char buf[1<<14],*p1=buf,*p2=buf;
#define GetC() ((p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++)
struct Ios{}io;
template <typename _tp>
Ios &operator >>(Ios &in,_tp &x){
	x=0;int w=0;char c=GetC();
	for(;!isdigit(c);w|=c=='-',c=GetC());
	for(;isdigit(c);x=x*10+(c^'0'),c=GetC());
	if(w) x=-x;
	return in;
}
const int N=5005,mod=1e9+7;
using ll=long long;
struct EDGE{int nxt,to;}e[N<<1];
int head[N],tot;
void add(int from,int to){
	e[++tot].nxt=head[from];
	e[tot].to=to;
	head[from]=tot;
}
int sz[N];
ll fac[N],inv[N],ifac[N];
ll C(int n,int m){
	if(m>n||m<0) return 0;
	return fac[n]*ifac[n-m]%mod*ifac[m]%mod;
}
int n;
int rt;
void dfs1(int u,int fa){
	sz[u]=1;
	int mx=0;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==fa) continue ;
		dfs1(v,u);
		mx=max(mx,sz[v]);
		sz[u]+=sz[v];
	}
	if(max(mx,n-sz[u])<=n/2) rt=u;
}
void dfs(int u,int fa){
	sz[u]=1;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==fa) continue ;
		dfs(v,u);
		sz[u]+=sz[v];
	}
}
ll dp[N];
int main(){
	io>>n;
	fac[0]=ifac[0]=1;fac[1]=inv[1]=ifac[1]=1;
	for(int i=2;i<=n;++i){
		fac[i]=fac[i-1]*i%mod;
		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		ifac[i]=ifac[i-1]*inv[i]%mod;
	}
	for(int i=1;i<n;++i){
		int u,v;io>>u>>v;
		add(u,v);add(v,u);
	}
	dfs1(1,0);
	dfs(rt,0);
	dp[0]=1;
	for(int i=head[rt];i;i=e[i].nxt){
		int v=e[i].to;
		for(int j=n;j>=0;--j){
			for(int k=1;k<=min(j,sz[v]);++k){
				dp[j]=(dp[j]+C(sz[v],k)*C(sz[v],k)%mod*dp[j-k]%mod*fac[k]%mod)%mod;
			}
		}
	}
	ll ans=0;
	for(int i=0;i<=n;++i){
		if(i&1) ans=(ans-dp[i]*fac[n-i]%mod)%mod;
		else ans=(ans+dp[i]*fac[n-i]%mod)%mod;
	}
	printf("%lld\n",(ans+mod)%mod);
	return 0;
}
posted @ 2022-11-19 16:34  pref_ctrl27  阅读(18)  评论(0编辑  收藏  举报