Atcoder 试题选做

[ARC087D] Squirrel Migration

瞎扯:考虑 \(dis(x,y)=dep_x+dep_y-2dep_{lca(x,y)}\),于是让 \(lca\) 最小即可。

易知如果根节点的最大的子树不超过一半,那么所有的 \(lca\) 都可以在根。如果大于一半呢,递归这棵子树吗?好像不太好做的样子。

正解:我在想马呢。直接选中心做根,完事了。后面的计算可以考虑容斥。所以这题凭什么铜牌?

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=5e3+10;
int n,m,mx,rt,R,ans;
int beg[N],nex[N<<1],to[N<<1],e;
inline void add(int x,int y){
	e++;nex[e]=beg[x];beg[x]=e;to[e]=y;
	e++;nex[e]=beg[y];beg[y]=e;to[e]=x;
}
int siz[maxn];
inline void dfs(int x,int fa){
	siz[x]=1;int Mx=0;
	for(int i=beg[x];i;i=nex[i]){
		int t=to[i];
		if(t==fa)continue;
		dfs(t,x);
		siz[x]+=siz[t];
		Mx=max(Mx,siz[t]);
	}Mx=max(Mx,n-siz[x]);
	if(Mx<mx)mx=Mx,rt=x;
}
int st[maxn],top,f[N],dp[N];
int fac[N],ifc[N],inv[N];
inline int com(int x,int y){
	if(x<y)return 0;
	return 1ll*fac[x]*ifc[y]%mod*ifc[x-y]%mod;
}
int main(){
	n=read();mx=inf;
	inv[1]=fac[0]=ifc[0]=1;
	for(int i=2;i<=n;i++)
		inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
	for(int i=1;i<=n;i++)
		fac[i]=1ll*fac[i-1]*i%mod;
	for(int i=1;i<=n;i++)
		ifc[i]=1ll*ifc[i-1]*inv[i]%mod;
	for(int i=1,x,y;i<n;i++)
		x=read(),y=read(),add(x,y);
	dfs(1,0);R=rt;dfs(rt,0);
	for(int i=beg[R];i;i=nex[i])
		st[++top]=siz[to[i]];
	dp[0]=1;f[0]=0;
	for(int i=1;i<=top;i++){
		for(int j=1;j<=st[i];j++)
			f[j]=1ll*com(st[i],j)*com(st[i],j)%mod*fac[j]%mod;
		for(int j=n;j>=0;j--)
			for(int k=0;k<=st[i]&&k<=j;k++)
				dp[j]=(dp[j]+1ll*dp[j-k]*f[k])%mod;
	}
	for(int i=0;i<=n;i++)
		if(~i&1)ans=(ans+1ll*dp[i]*fac[n-i])%mod;
		else ans=(ans+mod-1ll*dp[i]*fac[n-i]%mod)%mod;
	printf("%d\n",ans);
	return 0;
}
上一篇:剑指 Offer 10- I. 斐波那契数列


下一篇:CF754D Fedor and coupons(优先队列)