1. 程式人生 > >game - 期望 - 點分治 - FFT

game - 期望 - 點分治 - FFT

題目大意:給一棵樹,每次隨機選擇一個點,將其所在連通塊點權都+1並且刪掉這個點,問最後所有點點權和的期望。
題解:
考慮這個過程是在隨機點分治,一個點的點權就是這個點的深度,即其祖先數量。
那麼考慮y在多少情況中能作為x的祖先,不難發現當且僅當x到y的路徑上(不包含y)的點被刪除時間都嚴格大於y。那麼顯然是有 n ! l

e n + 1 \frac{n!}{\mathrm{len}+1} 種。
因此只要統計距離為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