game - 期望 - 點分治 - FFT
阿新 • • 發佈:2018-12-30
題目大意:給一棵樹,每次隨機選擇一個點,將其所在連通塊點權都+1並且刪掉這個點,問最後所有點點權和的期望。
題解:
考慮這個過程是在隨機點分治,一個點的點權就是這個點的深度,即其祖先數量。
那麼考慮y在多少情況中能作為x的祖先,不難發現當且僅當x到y的路徑上(不包含y)的點被刪除時間都嚴格大於y。那麼顯然是有
種。
因此只要統計距離為len的點有多少即可,點分+FFT。
注意一個問題是直接依次合併子樹是錯的,要麼從小到大排個序,要麼總的減去來自同一棵子樹的。
總的減去來自同一顆子樹的:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 1000000007
#define ull unsigned lint
#define db double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace INPUT_SPACE{
const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;
char gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
inline int inn()
{
int x,ch;while((ch=gc())<'0'||ch>'9');
x=ch^'0';while((ch=gc())>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
}using INPUT_SPACE::inn;
const int N=400010;
struct edges{
int to,pre;
}e[N<<1];int h[N],etop,fac[N],facinv[N],inv[N];
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
inline int prelude(int n)
{
rep(i,fac[0]=1,n) fac[i]=(lint)fac[i-1]*i%mod;
facinv[n]=fast_pow(fac[n],mod-2);
for(int i=n-1;i>=0;i--) facinv[i]=(i+1ll)*facinv[i+1]%mod;
rep(i,1,n) inv[i]=(lint)fac[i-1]*facinv[i]%mod;return 0;
}
namespace FFT_space{
const int N=(131072+5)<<2;
const db PI=acos(-1);
struct E{
db x,y;E(db _x=0.0,db _y=0.0){ x=_x,y=_y; }
inline E operator=(const E &w) { x=w.x,y=w.y;return *this; }
inline E operator+(const E &w)const { return E(x+w.x,y+w.y); }
inline E operator-(const E &w)const { return E(x-w.x,y-w.y); }
inline E operator*(const E &w)const { return E(x*w.x-y*w.y,x*w.y+y*w.x); }
inline E operator*=(const E &w) { return (*this)=(*this)*w; }
}A[N],B[N];int r[N];
inline int FFT(E *a,int n,int sgn)
{
rep(i,1,n-1) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<n;i<<=1)
{
E wn(cos(PI/i),sgn*sin(PI/i));
for(int j=0,p=i<<1;j<n;j+=p)
{
E w(1,0);
for(int k=0;k<i;k++,w*=wn)
{
E x=a[j+k],y=w*a[j+k+i];
a[j+k]=x+y,a[j+k+i]=x-y;
}
}
}
return 0;
}
inline int tms(int *a,int m1,int *b,int m2,lint *c)
{
if(max(m1,m2)<=50)
{
rep(i,0,m1+m2) c[i]=0;
rep(i,0,m1) if(a[i]) rep(j,0,m2)
if(b[j]) c[i+j]+=(lint)a[i]*b[j];
return 0;
}
int n=1,L=0;while(n<=m1+m2) n<<=1,L++;
rep(i,1,n-1) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
rep(i,0,n-1) A[i]=E(i<=m1?a[i]:0,0);
rep(i,0,n-1) B[i]=E(i<=m2?b[i]:0,0);
FFT(A,n,1),FFT(B,n,1);
rep(i,0,n-1) A[i]*=B[i];
FFT(A,n,-1);
rep(i,0,m1+m2) c[i]=(lint)(A[i].x/n+0.5);
return 0;
}
inline int pls(lint *a,lint *b,int n) { rep(i,0,n) a[i]+=b[i];return 0; }
inline int pls(int *a,int *b,int n) { rep(i,0,n) a[i]+=b[i];return 0; }
inline lint mns(lint *a,lint *b,int n) { rep(i,0,n) a[i]-=b[i];return 0; }
}using FFT_space::tms;using FFT_space::pls;using FFT_space::mns;
namespace subtask45{
lint cnt[N],tmp[N];
int vis[N],sz[N];
int dcx[N],dcy[N],dx,dy;
int lst[N],top;
int getsz(int x,int fa=0)
{
sz[x]=1,lst[++top]=x;
for(int i=h[x],y;i;i=e[i].pre)
if(!vis[y=e[i].to]&&e[i].to!=fa) sz[x]+=getsz(y,x);
return sz[x];
}
int getrt(int &x)
{
for(int i=1,fsz=sz[x],t=sz[x];i<=top;i++)
{
int y=lst[i],ysz=fsz-sz[y];
for(int j=h[y],z;j;j=e[j].pre) if(!vis[z=e[j].to])
{ if(sz[z]<sz[y]) ysz=max(ysz,sz[z]); }
if(ysz<t) t=ysz,x=y;
}
return 0;
}
int getdcy(int x,int fa,int d)
{
dcy[d]++,dy=max(dy,d);
for(int i=h[x],y;i;i=e[i].pre)
if(!vis[y=e[i].to]&&e[i].to!=fa) getdcy(y,x,d+1);
return 0;
}
int dfz(int x)
{
top=0,getsz(x),getrt(x),vis[x]=1,dcx[0]=1,dx=0,cnt[0]++;
for(int i=h[x],y;i;i=e[i].pre) if(!vis[y=e[i].to])
dy=0,getdcy(y,0,1),pls(dcx,dcy,dy),dx=max(dx,dy),
tms(dcy,dy,dcy,dy,tmp),mns(cnt,tmp,dy<<1),
memset(dcy,0,sizeof(int)*(dy+1));
tms(dcx,dx,dcx,dx,tmp),pls(cnt,tmp,dx<<1);
memset(dcx,0,sizeof(int)*(dx+1));
for(int i=h[x],y;i;i=e[i].pre) if(!vis[y=e[i].to]) dfz(y);
return 0;
}
inline int acceptable_solution(int n)
{
dfz(1);int ans=0;cnt[0]-=n;
rep(i,0,n-1) ans=(ans+cnt[i]*inv[i+1])%mod;
ans=(lint)ans*fac[n]%mod;return !printf("%d\n",ans);
}
}
int main()
{
int n=inn(),x,y;prelude(n);
rep(i,1,n-1) x=inn(),y=inn(),add_edge(x,y),add_edge(y,x);
return subtask45::acceptable_solution(n);
}
排序後依次合併的:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 1000000007
#define ull unsigned lint
#define db