[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);
}

相关文章:

  • 2021-10-18
  • 2022-12-23
  • 2022-12-23
  • 2020-10-18
  • 2021-08-16
  • 2022-12-23
猜你喜欢
  • 2021-09-26
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-11-20
  • 2022-12-23
  • 2021-11-05
相关资源
相似解决方案