zoukankan      html  css  js  c++  java
  • Forest Program(2019ccpc秦皇岛F)

    题:http://acm.hdu.edu.cn/showproblem.php?pid=6736

    题意:删掉一些边使得图不存在点双,求方案数。

    分析:若一条边不属于点双,那么这条边有删和不删俩种选择,若找到点双,点双中必须删掉一条边(题目有保证一条边只能属于一个点双,所以不用担心一条边用于多个点双)tarjan找点双,若为点双则必须删掉点双中的一条边

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    #define pii pair<int,int>
    const int M=3e5+5;
    const int mod=998244353;
    vector<int>g[M];
    //vector<pii>bcc[M];
    pii stk[M];
    int low[M],dfn[M],tot,top,cnt;
    ll countt[M];
    void tarjan(int u,int f){
        low[u]=dfn[u]=++tot;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            pii e=make_pair(u,v);
            if(!dfn[v]){
                stk[++top]=e;
                tarjan(v,u);
                low[u]=min(low[u],low[v]);
                if(low[v]>=dfn[u]){
                    cnt++;
                    int len=top;
                    while(stk[top]!=e){
                        //bcc[cnt].pb(stk[top--]);
                        top--;
                    }
                    //bcc[cnt].pb(stk[top--]);
                    top--;
                    countt[cnt]=len-top;
                }
            }
            else if(v!=f){
                if(dfn[v]<dfn[u])
                    stk[++top]=e,low[u]=min(low[u],dfn[v]);
            }
        }    
    }
    ll ksm(ll a,ll b){
        ll t=1ll;
        while(b){
            if(b&1)
                t=(t*a)%mod;
            b>>=1;
            a=(a*a)%mod;
        }
        return t;
    }
    ll mi[M];
    int main(){
        for(int i=0;i<=M-5;i++)
            mi[i]=ksm(2ll,1ll*i);
        //cout<<mi[3]<<endl;
        int n,m;
        while(~scanf("%d%d",&n,&m)){
            tot=top=cnt=0;
            for(int i=0;i<=n;i++)
                low[i]=dfn[i]=0,countt[i]=0,g[i].clear();
            for(int i=1;i<=m;i++){
                int u,v;
                scanf("%d%d",&u,&v);
                g[u].pb(v);
                g[v].pb(u);
            }
            for(int i=1;i<=n;i++)
                if(!dfn[i])
                    tarjan(i,-1);
            
            ll ans=1ll;
        //    cout<<"cnt"<<cnt<<endl;
            for(int i=1;i<=cnt;i++){
                if(countt[i]>1){
                    ans*=mi[countt[i]]-1;
                    m-=countt[i];
                    ans%=mod;
                }
                
            }
            if(m>=1)
                ans*=mi[m];
            printf("%lld
    ",ans%mod);
        }
        return 0;
    }
    View Code

    经验:得重新认识点双和边双,清楚定义

  • 相关阅读:
    POJ 2329 Nearest number
    POJ 2192 Zipper (简单DP)
    POJ 2231 Moo Volume(递推、前缀和)
    数据库增删改查--2017-04-08
    时间戳--2017-04-07
    数据库三大范式---2017-04-07
    数据库主键和外键----数据库基础知识1---2017-04-07
    登录页面(简单版,带遮罩层)---2017-04-06 (与04-05日写的差不多,界面圆滑点)
    第一阶段项目所遇到的问题---2017-04-066
    图片点击轮播(四)高级--2017-04-05
  • 原文地址:https://www.cnblogs.com/starve/p/11609939.html
Copyright © 2011-2022 走看看