[CCPC2019秦皇岛 F]
Link
https://codeforces.com/gym/102361/problem/F
Description
给定一个仙人掌,删去一些边可以让它变成一个森林(一棵树也是森林),求方案数。 \(n \le 300000, m \le 500000\)
Solution
用 DFS 暴力找环,然后乘法原理算一下即可。注意非环边也会有贡献。
DFS 可以模仿 Tarjan 算法写。
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 300005;
const int modulo = 998244353;
vector <int> g[N];
int is[N],dis[N];
int n,m,t1,t2,t3,t4;
vector <int> sta,cir;
int qpow(int p,int q)
{
int r=1;
for(;q;p*=p,p%=modulo,q>>=1) if(q&1) r*=p,r%=modulo;
return r;
}
void dfs(int p,int dep)
{
is[p]=2;
dis[p]=dep;
sta.push_back(p);
for(int i=0;i<g[p].size();i++)
{
int q=g[p][i];
if(is[q]==2 && dep-dis[q]>1)
{
cir.push_back(dep+1-dis[q]);
}
else if(is[q]==0)
{
dfs(q,dep+1);
}
}
sta.pop_back();
is[p]=1;
}
signed main()
{
scanf("%I64d%I64d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%I64d%I64d",&t1,&t2);
g[t1].push_back(t2);
g[t2].push_back(t1);
}
for(int i=1;i<=n;i++)
{
if(is[i]==0)
{
dfs(i,1);
}
}
int sum=0,ans=1;
for(int i=0;i<cir.size();i++)
{
ans*=(qpow(2ll,cir[i])-1ll);
ans%=modulo;
ans+=modulo;
ans%=modulo;
sum+=cir[i];
}
ans*=qpow(2ll,m-sum);
ans%=modulo;
printf("%I64d\n",ans);
}
原文地址:https://www.cnblogs.com/mollnn/p/11730147.html
时间: 2024-10-30 07:38:11