[??记录]AT3728 [ARC087D] Squirrel Migration
command_block · · 个人记录
题意 : 给出一棵
求使得
答案对
将各个颜色的方案卷积(背包)起来即可。复杂度为
若利用分治
-
有两个重心
找出连接两个重心的边,两侧的点数都恰好是
n/2 。只需要两侧的点之间随意匹配即可,方案数为
(n/2)!^2 。
#include<algorithm>
#include<cstdio>
#include<vector>
#define pb push_back
#define ll long long
#define MaxN 5050
using namespace std;
vector<int> g[MaxN];
int n,rt,siz[MaxN];
void dfs(int u)
{
siz[u]=1;
for (int i=0,v;i<g[u].size();i++)
if (!siz[v=g[u][i]]){
dfs(v);
siz[u]+=siz[v];
}
if (!rt&&siz[u]*2>=n)rt=u;
}
const int mod=1000000007;
ll powM(ll a,int t=mod-2){
ll ret=1;
while(t){
if (t&1)ret=ret*a%mod;
t>>=1;a=a*a%mod;
}return ret;
}
ll fac[MaxN],ifac[MaxN];
void Init(int n)
{
fac[0]=1;
for (int i=1;i<=n;i++)
fac[i]=fac[i-1]*i%mod;
ifac[n]=powM(fac[n]);
for (int i=n;i;i--)
ifac[i-1]=ifac[i]*i%mod;
}
ll F[MaxN],G[MaxN],S[MaxN];
int main()
{
scanf("%d",&n);Init(n);
for (int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
g[u].pb(v);g[v].pb(u);
}
dfs(1);int sav=rt;
for (int i=1;i<=n;i++)siz[i]=0;
dfs(rt);
bool fl=0;
for (int i=2;i<=n;i++)
fl|=(siz[i]*2==n);
if (fl){
printf("%lld",fac[n/2]*fac[n/2]%mod);
return 0;
}
int m=0;F[0]=1;
for (int j=0;j<g[sav].size();j++){
int c=siz[g[sav][j]];
for (int i=0;i<=m;i++){S[i]=F[i];F[i]=0;}
for (int k=0;k<=c;k++){
ll G=fac[c]*ifac[k]%mod*ifac[c-k]%mod*fac[c]%mod*ifac[c-k]%mod;
for (int i=0;i<=m;i++)
F[i+k]=(F[i+k]+S[i]*G)%mod;
}m+=c;
}
ll ans=0;
for (int i=0;i<=n;i++){
ll buf=F[i]*fac[n-i]%mod;
if (i&1)ans-=buf;else ans+=buf;
}printf("%lld",(ans%mod+mod)%mod);
return 0;
}