[DS记录]CFgym101234D Forest Game
command_block · · 个人记录
题目Link
题意 : 在树上随机点分治,问期望复杂度。对
这是分式求和,难以批量维护,只好记录分母为状态。
我们分别统计长度为
求
对于某个分治中心,记录到根距离为
那么子树的路径拼合的贡献就是
此外可能把来自同一棵子树的路径拼了起来,所以还要减去每个子树内的答案。方法类似。
这题模数并不是NTT模数,只好使用FFT。
注意这题卷积得到的最大数可达
具体实现时,点分治数边数然后+1得到点数更方便。
注意
写数组版会快,但是注意清空。中间强制转换int挂了几次……
复杂度
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#define ll long long
#define mod 1000000007
#define MaxN 100500
using namespace std;
const double Pi=acos(-1);
ll powM(ll a,int t=mod-2)
{
ll ans=1;
while(t){
if (t&1)ans=ans*a%mod;
a=a*a%mod;
t>>=1;
}return ans;
}
struct CP
{
CP (double xx=0,double yy=0){x=xx,y=yy;}
double x,y;
CP operator + (CP const &B) const
{return CP(x+B.x,y+B.y);}
CP operator - (CP const &B) const
{return CP(x-B.x,y-B.y);}
CP operator * (CP const &B) const
{return CP(x*B.x-y*B.y,x*B.y+y*B.x);}
}S[270000];
int tr[270000];
void FFT(CP *f,int n,bool flag)
{
for (int i=0;i<n;i++)
if (i<tr[i])swap(f[i],f[tr[i]]);
for(int p=2;p<=n;p<<=1){
int len=p>>1;
CP tG(cos(2*Pi/p),sin(2*Pi/p));
if(!flag)tG.y*=-1;
for(int k=0;k<n;k+=p){
CP buf(1,0);
for(int l=k;l<k+len;l++){
CP tt=buf*f[len+l];
f[len+l]=f[l]-tt;
f[l]=f[l]+tt;
buf=buf*tG;
}
}
}
}
void sqr(ll *F,int m)
{
for (int i=0;i<=m;i++)S[i].y=S[i].x=F[i];
int n=1;for(m<<=1;n<=m+1;n<<=1);
for(int i=0;i<n;i++)
tr[i]=(tr[i>>1]>>1)|((i&1)?n>>1:0);
FFT(S,n,1);
for(int i=0;i<n;i++)S[i]=S[i]*S[i];
FFT(S,n,0);
for(int i=0;i<=m;i++)
F[i]=(ll)(S[i].y/n/2+0.49);
memset(S,0,sizeof(CP)*(n+5));
}
vector<int> g[MaxN];
int tp[MaxN],tn,ms[MaxN],siz[MaxN];
bool vis[MaxN];
void pfs(int u,int fa)
{
tp[++tn]=u;
siz[u]=1;ms[u]=0;
for (int i=0,v;i<g[u].size();i++)
if ((v=g[u][i])!=fa&&!vis[v]){
pfs(v,u);
siz[u]+=siz[v];
ms[u]=max(ms[u],siz[v]);
}
}
int getrt(int u)
{
tn=0;pfs(u,0);
int rt=0;
for (int i=1;i<=tn;i++){
ms[tp[i]]=max(ms[tp[i]],tn-siz[tp[i]]);
if (ms[tp[i]]<ms[rt])rt=tp[i];
}return rt;
}
ll t1[MaxN],t2[MaxN];int lim;
void dfs(int u,int fa,int len)
{
lim=max(lim,len);
t2[len]++;
for (int i=0,v;i<g[u].size();i++)
if ((v=g[u][i])!=fa&&!vis[v])
dfs(v,u,len+1);
}
ll c[MaxN];
void clac(int u)
{
int l2=0;t1[0]++;
for (int i=0;i<g[u].size();i++)
if (!vis[g[u][i]]){
lim=0;
dfs(g[u][i],u,1);
l2=max(l2,lim);
for (int i=0;i<=lim;i++)
t1[i]+=t2[i];
sqr(t2,lim);
for (int i=0;i<=lim+lim;i++)
c[i]-=t2[i];
memset(t2,0,sizeof(ll)*(lim*2+5));
}
sqr(t1,l2);
for (int i=0;i<=l2+l2;i++)
c[i]+=t1[i];
memset(t1,0,sizeof(ll)*(l2*2+5));
}
void solve(int u)
{
clac(u);vis[u]=1;
for (int i=0,v;i<g[u].size();i++)
if (!vis[v=g[u][i]])
solve(getrt(v));
}
int n;
int main()
{
scanf("%d",&n);
for (int i=1,fr,to;i<n;i++){
scanf("%d%d",&fr,&to);
g[fr].push_back(to);
g[to].push_back(fr);
}ms[0]=n;solve(getrt(1));
ll ans=0;
for (int i=0;i<n;i++)
ans=(ans+c[i]%mod*powM(i+1))%mod;
for (int i=1;i<=n;i++)ans=ans*i%mod;
printf("%I64d",ans);
}