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 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=100010;
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=200000;
    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)
        {
            memset(c,0,sizeof(lint)*(m1+m2+1));
            rep(i,0,m1) rep(j,0,m2) 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; }
}using FFT_space::tms;using FFT_space::pls;
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;
    }
    pii L[N];
    int getdpt(int x,int fa)
    {
        int d=0;
        for(int i=h[x],y;i;i=e[i].pre)
            if(!vis[y=e[i].to]&&e[i].to!=fa) d=max(d,getdpt(y,x)+1);
        return d;
    }
    int dfz(int x)
    {
        top=0,getsz(x),getrt(x),vis[x]=1,dcx[0]=1,dx=0,cnt[0]++;int t=0;
        for(int i=h[x],y;i;i=e[i].pre)
            if(!vis[y=e[i].to]) L[++t]=mp(getdpt(y,x),y);
        sort(L+1,L+t+1);
        for(int i=1,y;i<=t;i++)
            y=L[i].sec,dy=0,getdcy(y,0,1),tms(dcx,dx,dcy,dy,tmp),
            pls(cnt,tmp,dx+dy),pls(dcx,dcy,dy),
            dx=max(dx,dy),memset(dcy,0,sizeof(int)*(dy+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;rep(i,1,n-1) cnt[i]=cnt[i]*2%mod;
        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);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/85090088