CF1236F - Alice and the Cactus

CF1236F - Alice and the Cactus

题目大意

给定一棵仙人掌,现在每个点有\(\frac{1}{2}\)概率被删除

设删除后剩余连通块数为\(\Chi\),求\(D(\Chi)\)\(D\)为方差)


分析

由简单结论\(D(\Chi)=E(\Chi^2)-E^2(\Chi)\)

考虑计算\(E(\Chi ^2),E(\Chi)\),也就是计算所有情况下\(\Chi^2,\Chi\)之和

实际上对于计算\(E(\Chi^k)\)的情况,可以记录\(E(\Chi^i),i\in[0,k]\)所有的答案

然后在仙人掌上\(dp\),每次合并两个\(dp\)时对于\((\Chi+\Chi')^i\)做二项展开计算答案

环上\(dp\)记录开头和结尾的一些状态即可

如果分裂出一个连通块,就对于当前\(\Chi^i\rightarrow (\Chi+1)^i\),同样是二项展开

具体不再赘述

复杂度为\(O(n)\)

const int N=5e5+10,P=1e9+7;

int n,m;
struct Node{
    int x,y,z;
    Node(){}
    Node(int x,int y,int z):x(x),y(y),z(z){}
    Node operator * (const Node t) const {
        return Node(1ll*x*t.x%P,
                (1ll*y*t.x+1ll*t.y*x)%P,
                (1ll*z*t.x+1ll*t.z*x+2ll*y*t.y)%P);
    }
    Node operator + (const Node t) const { 
        return Node((x+t.x)%P,(y+t.y)%P,(z+t.z)%P);
    }
    Node operator + (const int t) const { 
        return Node(x,(y+1ll*t*x)%P,(z+2ll*y*t+1ll*x*t%P*t%P)%P);
    }
    Node operator * (const int t) const {
        return Node(1ll*x*t%P,1ll*y*t%P,1ll*z*t%P);
    }
} dp[N][2],f[N][2][3];

struct Edge{
    int to,nxt;
} e[N<<1];
int head[N],ecnt;
void AddEdge(int u,int v) {
    e[++ecnt]=(Edge){v,head[u]};
    head[u]=ecnt;
}

int low[N],t[N],dfn,stk[N],top;
int A[N],C;
void dfs(int u) {
    low[u]=t[u]=++dfn,stk[++top]=u;
    dp[u][0]=Node(1,0,0),dp[u][1]=Node(1,0,0);
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].to;
        if(t[v]) {
            cmin(low[u],t[v]);
            continue;
        }
        dfs(v),cmin(low[u],low[v]);
        if(low[v]<t[u]) continue;
        A[C=1]=u;
        while(t[stk[top]]>=t[v]) A[++C]=stk[top--];
        rep(i,1,C) rep(a,0,1) rep(b,0,2) f[i][a][b]=Node(0,0,0);
        f[1][0][0]=dp[u][0], f[1][1][2]=dp[u][1];
        rep(i,2,C) {
            rep(a,0,1) rep(b,0,2) {
                rep(c,0,1) {
                    int d=c==1 && b==2?b:c;
                    f[i][a][d]=f[i][a][d]+(f[i-1][a][b]*dp[A[i]][c]+(b==1 && !c));
                }
            }
        }
        dp[u][0]=dp[u][1]=Node(0,0,0);
        rep(a,0,1) rep(b,0,2) {
            dp[u][a]=dp[u][a]+(f[C][a][b]+(b==1 && !a));
        }
    }
}

int main(){
    n=rd(),m=rd();
    rep(i,1,m) {
        int u=rd(),v=rd();
        AddEdge(u,v),AddEdge(v,u);
    }
    dfs(1);
    int base=1;
    rep(i,1,n) base=1ll*base*(P+1)/2%P;
    Node ans=dp[1][0]+(dp[1][1]+1);
    ans=ans*base;
    int D=((ans.z-1ll*ans.y*ans.y)%P+P)%P;
    printf("%d\n",D);
}

posted @ 2021-05-26 20:35  chasedeath  阅读(65)  评论(0编辑  收藏  举报