您的位置:首页 > 其它

Codeforces Gym 101234D Forest Game

2017-06-18 21:36 495 查看
我们枚举两个点,考虑它们之间的贡献。如果u和v之间的距离为d,那么u对v有1的贡献当且仅当这条路径上v被第一个删除,概率是1d+1。因此我们只需要求出这些点两两之间的距离。点分治的时候用FFT计算就可以了,复杂度O(nlog2n)。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define LL long long
const int maxn=400010,p=1000000007;
const double pi=acos(-1);
struct Complex
{
double a,b;
Complex operator + (const Complex &c) const
{
return (Complex){a+c.a,b+c.b};
}
Complex operator - (const Complex &c) const
{
return (Complex){a-c.a,b-c.b};
}
Complex operator * (const Complex &c) const
{
return (Complex){a*c.a-b*c.b,a*c.b+b*c.a};
}
Complex operator / (const double &x) const
{
return (Complex){a/x,b/x};
}
}f[maxn],g[maxn],w[maxn];
vector<int> to[maxn];
int size[maxn],val[maxn],vis[maxn],cnt[maxn],c1[maxn],tot[maxn],rev[maxn],
n;
int inc(int x,int y)
{
x+=y;
return x>=p?x-p:x;
}
int dec(int x,int y)
{
x-=y;
return x<0?x+p:x;
}
int pow(int b,int k)
{
int ret=1;
for (;k;k>>=1,b=(LL)b*b%p)
if (k&1) ret=(LL)ret*b%p;
return ret;
}
int dfs2(int u,int fa,int S)
{
int ret=-1,v;
size[u]=1;
val[u]=0;
for (vector<int>::iterator it=to[u].begin();it!=to[u].end();++it)
if (!vis[*it]&&*it!=fa)
{
v=dfs2(*it,u,S);
if (ret==-1||val[v]<val[ret]) ret=v;
size[u]+=size[*it];
val[u]=max(val[u],size[*it]);
}
val[u]=max(val[u],S-size[u]);
if (ret==-1||val[u]<val[ret]) ret=u;
return ret;
}
void dfs3(int u,int fa)
{
size[u]=1;
for (vector<int>::iterator it=to[u].begin();it!=to[u].end();++it)
if (!vis[*it]&&*it!=fa)
{
dfs3(*it,u);
size[u]+=size[*it];
}
}
int dfs4(int u,int fa,int d)
{
int ret=d;
c1[d]++;
for (vector<int>::iterator it=to[u].begin();it!=to[u].end();++it)
if (!vis[*it]&&*it!=fa)
ret=max(ret,dfs4(*it,u,d+1));
return ret;
}
void fft(Complex *a,int m,int t,int flag)
{
int x;
Complex t1,t2;
for (int i=0;i<m;i++)
if (rev[i]>i) swap(a[i],a[rev[i]]);
for (int i=0;i<t;i++)
for (int j=0;j<m;j+=1<<(i+1))
{
x=0;
for (int k=j;k<j+(1<<i);k++)
{
t1=a[k];
t2=a[k+(1<<i)]*w[x];
a[k]=t1+t2;
a[k+(1<<i)]=t1-t2;
x+=flag*(1<<(t-i-1));
if (x<0) x+=m;
}
}
if (flag==-1)
for (int i=0;i<m;i++) a[i]=a[i]/m;
}
void dfs1(int u,int S)
{
int mx=0,m1,l,t,r;
for (int i=1;i<=S;i++) cnt[i]=0;
cnt[0]=1;
r=dfs2(u,-1,S);
vis[r]=1;
dfs3(r,-1);
for (vector<int>::iterator it=to[r].begin();it!=to[r].end();++it)
if (!vis[*it])
{
for (int i=0;i<=size[*it];i++) c1[i]=0;
m1=dfs4(*it,r,1);
l=1,t=0;
while (l<=2*m1) l<<=1,t++;
for (int i=0;i<=m1;i++) f[i]=(Complex){(double)c1[i],0.0};
for (int i=m1+1;i<l;i++) f[i]=(Complex){0,0};
for (int i=0;i<l;i++) w[i]=(Complex){cos(2*pi*i/l),sin(2*pi*i/l)};
for (int i=0;i<l;i++)
{
rev[i]=0;
for (int j=0;j<t;j++)
rev[i]|=((i>>j)&1)<<(t-j-1);
}
fft(f,l,t,1);
for (int i=0;i<l;i++) f[i]=f[i]*f[i];
fft(f,l,t,-1);
for (int i=0;i<l;i++) tot[i]=dec(tot[i],((LL)(f[i].a+0.5))%p);
for (int i=0;i<=m1;i++) cnt[i]+=c1[i];
mx=max(mx,m1);
}
l=1,t=0;
while (l<=2*mx) l<<=1,t++;
for (int i=0;i<=mx;i++) f[i]=(Complex){(double)cnt[i],0.0};
for (int i=mx+1;i<l;i++) f[i]=(Complex){0,0};
for (int i=0;i<l;i++) w[i]=(Complex){cos(2*pi*i/l),sin(2*pi*i/l)};
for (int i=0;i<l;i++)
{
rev[i]=0;
for (int j=0;j<t;j++)
rev[i]|=((i>>j)&1)<<(t-j-1);
}
fft(f,l,t,1);
for (int i=0;i<l;i++) f[i]=f[i]*f[i];
fft(f,l,t,-1);
for (int i=0;i<l;i++) tot[i]=inc(tot[i],((LL)(f[i].a+0.5))%p);
for (vector<int>::iterator it=to[r].begin();it!=to[r].end();++it)
if (!vis[*it]) dfs1(*it,size[*it]);
}
int main()
{
//freopen("g.in","r",stdin);
int ans=0,x,y;
scanf("%d",&n);
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
to[x].push_back(y);
to[y].push_back(x);
}
dfs1(1,n);
for (int i=0;i<n;i++)
ans=inc(ans,(LL)tot[i]*pow(i+1,p-2)%p);
for (int i=2;i<=n;i++) ans=(LL)ans*i%p;
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: