队友过的:https://blog.csdn.net/liufengwei1/article/details/101632506
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 124 Accepted Submission(s): 47
找出所有环,每个环至少选择一条边删掉,那么方案数就是2^size-1,不在环上的边为m条,可以随便删,方案数就是2^resm。
点双抄一遍就过了,也可以直接dfs
#include<bits/stdc++.h> #define maxl 500010 using namespace std; const int mod=998244353; int n,m,top,cnt,ind,sum,rt,dcccnt; vector <int> dcc[maxl]; long long ans; int dfn[maxl],low[maxl],ehead[maxl],s[maxl]; long long num[maxl]; bool in[maxl],cut[maxl]; struct ed { int to,nxt; }e[maxl<<1]; inline void add(int u,int v) { e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt; } inline void tarjan(int u) { dfn[u]=low[u]=++ind;s[++top]=u; if(u==rt && ehead[u]==0) { dcc[++dcccnt].push_back(u); return; } int son=0,v; for(int i=ehead[u];i;i=e[i].nxt) { v=e[i].to; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]) { son++; if(u!=rt || son>1) cut[u]=true; dcccnt++; int d; do { d=s[top--]; dcc[dcccnt].push_back(d); }while(d!=v); dcc[dcccnt].push_back(u); } } else low[u]=min(low[u],dfn[v]); } } inline void prework() { for(int i=1;i<=dcccnt;i++) dcc[i].clear(); dcccnt=0; for(int i=1;i<=n;i++) { dfn[i]=low[i]=0;in[i]=false; ehead[i]=0;cut[i]=false; } int u,v;cnt=1; for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v); add(u,v);add(v,u); } ind=0; for(int i=1;i<=n;i++) if(dfn[i]==0) { rt=i;top=0; tarjan(i); } } inline void mainwork() { int resm=m; ans=1; for(int i=1;i<=dcccnt;i++) { sum=dcc[i].size(); if(sum>=3) ans=ans*num[sum]%mod,resm-=sum; } ans=ans*(num[resm]+1)%mod; } inline void print() { printf("%lld\n",ans); } int main() { //freopen("1006.in","r",stdin); num[0]=1; for(int i=1;i<maxl;i++) num[i]=2ll*num[i-1]%mod; for(int i=0;i<maxl;i++) num[i]=((num[i]-1)%mod+mod)%mod; while(~scanf("%d%d",&n,&m)) { prework(); mainwork(); print(); } return 0; }
原文:https://www.cnblogs.com/songorz/p/11604635.html