zoukankan      html  css  js  c++  java
  • [HNOI/AHOI2018]毒瘤

    题目描述

    https://www.lydsy.com/JudgeOnline/upload/201804/%E6%B9%96%E5%8D%97%E4%B8%80%E8%AF%95%E8%AF%95%E9%A2%98.pdf

    题解

    大意:给出一张n个点n+x条边的无向连通图,x很小,求出这个图上最大独立集的方案数。

    感觉就是NOIP保卫王国那题的加强版吧。

    暴力的话,我们可以考虑在图上随便找一颗生成树,然后把非树边连接的点设置为关键点,然后2^x枚举这些点的选择情况,每次做一遍树形dp就好了。

    如果做到这里,那么可以自然而然的想到一个优化:虚树。

    就是发现在虚树上的非关键点部分的转移相似,所以我们可以预处理出这些东西来。

    我们设f[i][0/1]表示i点的所有不包含关键点的子树的答案。

    对于关键点到关键点的转移,我们可以设k[i][0/1][0/1]表示关键点i点到i点的第一个关键点祖先的儿子处i点和那个儿子的选择情况的方案数。

    这个直接从i点向上跳,边跳边统计答案就可以算出来了。

    注意虚树上的LCA点也要标为关键点。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #define N 110009
    using namespace std;
    typedef long long ll;
    const int mod=998244353;
    vector<int>vec[N];
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    } 
    struct node{int u,v;}ed[50];
    ll k[N][2][2],g[N][2],f[N][2],ans;
    int tot,head[N],dfn[N],p[19][N],deep[N],a[N],ttt,n,m,st[N],top;
    bool vis[N],dy1[N],dy0[N],tag[N];
    struct edge{int n,to;}e[N<<1];
    inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
    inline void add2(int u,int v){tag[u]=1;tag[v]=1;vec[u].push_back(v);}////!!!!!!!!!
    void dfs(int u,int fa){
        dfn[u]=++dfn[0];vis[u]=1;
        for(int i=1;(1<<i)<=deep[u];++i)p[i][u]=p[i-1][p[i-1][u]];
        for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
            int v=e[i].to;
            if(!vis[v]){deep[v]=deep[u]+1;p[0][v]=u;dfs(v,u);}
            else{a[++a[0]]=u;a[++a[0]]=v;ed[++ttt]=node{u,v};}
        }
    }
    inline bool cmp(int a,int b){return dfn[a]<dfn[b];}
    inline int getlca(int a,int b){
        if(deep[a]<deep[b])swap(a,b);
        for(int i=17;i>=0;--i)if(deep[a]-(1<<i)>=deep[b])a=p[i][a];
        if(a==b)return a;
        for(int i=17;i>=0;--i)if(p[i][a]!=p[i][b])a=p[i][a],b=p[i][b];
        return p[0][a];
    }
    void predp(int u,int jin){
        f[u][0]=f[u][1]=1;tag[u]=1;
        for(int i=head[u];i;i=e[i].n){
            int v=e[i].to;
            if(p[0][v]!=u||v==jin||tag[v])continue;
            predp(v,jin);
            f[u][0]=f[u][0]*(f[v][0]+f[v][1])%mod;
            f[u][1]=f[u][1]*f[v][0]%mod;
        }
    }
    inline void getnum(int x,int y){
        k[x][0][0]=k[x][1][1]=1;
        for(int i=x;p[0][i]!=y;i=p[0][i]){
            predp(p[0][i],i);
            ll xx=k[x][0][0],yy=k[x][1][0];
            k[x][0][0]=f[p[0][i]][0]*(k[x][0][1]+k[x][0][0])%mod;
            k[x][0][1]=f[p[0][i]][1]*xx%mod;
            k[x][1][0]=f[p[0][i]][0]*(k[x][1][0]+k[x][1][1])%mod;
            k[x][1][1]=f[p[0][i]][1]*yy%mod;                              
        }
    }
    void prework(int u){
        for(int i=0;i<vec[u].size();++i){
            int v=vec[u][i];
            prework(v);getnum(v,u);
        }    
        f[u][0]=f[u][1]=1;
        for(int i=head[u];i;i=e[i].n){
            int v=e[i].to;
            if(p[0][v]!=u||tag[v])continue;
            predp(v,0);
            f[u][0]=f[u][0]*(f[v][0]+f[v][1])%mod;
            f[u][1]=f[u][1]*f[v][0]%mod;
        }
    }
    void dp(int u){
        g[u][0]=f[u][0];g[u][1]=f[u][1];
        if(dy1[u])g[u][0]=0;if(dy0[u])g[u][1]=0;
        for(int i=0;i<vec[u].size();++i){
            int v=vec[u][i];
            dp(v);
            ll k0=(k[v][0][0]*g[v][0]%mod+k[v][1][0]*g[v][1]%mod)%mod,k1=(k[v][0][1]*g[v][0]%mod+k[v][1][1]*g[v][1]%mod)%mod;
            g[u][0]=g[u][0]*(k0+k1)%mod;g[u][1]=g[u][1]*k0%mod;
        }
    }
    int main(){
        n=rd();m=rd();int u,v;
        for(int i=1;i<=m;++i){
            u=rd();v=rd();
            add(u,v);add(v,u);    
        }
        dfs(1,0);sort(a+1,a+a[0]+1,cmp);
        a[0]=unique(a+1,a+a[0]+1)-a-1;
        st[top=1]=1;
        for(int i=1;i<=a[0];++i){
            tag[a[i]]=1;
            if(a[i]==st[top])continue;
            int lca=getlca(st[top],a[i]);
            if(lca==st[top]){st[++top]=a[i];continue;}
            while(top>1){
                int x=st[top],y=st[top-1];
                if(dfn[lca]>=dfn[y]){add2(lca,x);top--;break;}
                add2(y,x);top--;
            }
            if(st[top]!=lca)st[++top]=lca;
            if(st[top]!=a[i])st[++top]=a[i];
        }
        while(top>1)add2(st[top-1],st[top]),top--;
        prework(1);
        for(int i=0;i<(1<<a[0]);++i){
            for(int j=1;j<=a[0];++j)if(i&(1<<j-1))dy1[a[j]]=1,dy0[a[j]]=0;else dy0[a[j]]=1,dy1[a[j]]=0;
            bool tagg=0;
            for(int j=1;j<=ttt;++j){
                int u=ed[j].u,v=ed[j].v;
                if(dy1[u]&&dy1[v]){tagg=1;break;} 
            }
            if(tagg)continue; 
            dp(1);
            (ans+=g[1][0]+g[1][1])%=mod;
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    Python之os模块
    Python之加密模块
    Python之random模块
    Python之操作MySQL数据库
    Python之操作Excel
    Jmeter之发送请求入参必须使用编码格式、Jmeter之发送Delete请求可能入参需要使用编码格式
    PAT B1008 数组元素循环右移问题 (20 分)
    PAT B1007 素数对猜想 (20 分)
    PAT B1006 换个格式输出整数 (15 分)
    PAT B1005 继续(3n+1)猜想 (25 分)
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10435484.html
Copyright © 2011-2022 走看看