cf Educational Codeforces Round 56 D. Beautiful Graph

原题:
D. Beautiful Graph
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output

You are given an undirected unweighted graph consisting of n vertices and m edges.

You have to write a number on each vertex of the graph. Each number should be 1, 2 or 3. The graph becomes beautiful if for each edge the sum of numbers on vertices connected by this edge is odd.

Calculate the number of possible ways to write numbers 1, 2 and 3 on vertices so the graph becomes beautiful. Since this number may be large, print it modulo 998244353.

Note that you have to write exactly one number on each vertex.

The graph does not have any self-loops or multiple edges.

Input
The first line contains one integer t (1≤t≤3⋅10^5) — the number of tests in the input.

The first line of each test contains two integers n and m (1≤n≤3⋅10^ 5,0≤m≤3⋅10^5) — the number of vertices and the number of edges, respectively. Next m lines describe edges: i-th line contains two integers ui, vi (1≤ui,vi≤n;ui≠vi) — indices of vertices connected by i-th edge.

It is guaranteed that ∑i=1tn≤3⋅10^ 5 and ∑i=1tm≤3⋅10^5.

Output
For each test print one line, containing one integer — the number of possible ways to write numbers 1, 2, 3 on the vertices of given graph so it becomes beautiful. Since answers may be large, print them modulo 998244353.

Example
input
2
2 1
1 2
4 6
1 2
1 3
1 4
2 3
2 4
3 4
output
4
0
Note
Possible ways to distribute numbers in the first test:

the vertex 1 should contain 1, and 2 should contain 2;
the vertex 1 should contain 3, and 2 should contain 2;
the vertex 1 should contain 2, and 2 should contain 1;
the vertex 1 should contain 2, and 2 should contain 3.
In the second test there is no way to distribute numbers.

中文:

给你一个数t,表示有t组数据,每一组数据给一个n和m,表示有一个无向图,有n个节点,m条边。现在让你用1,2,3这三个数,标记在节点上,使得每一条边上的两个节点的标号和是奇数。最后问你有多少种标号方法,结果取模。如果不能标号,输出0

代码:

#include<bits/stdc++.h>
using namespace std;
#define make_pair mp

const int maxn = 3e5+1;

typedef long long ll;
typedef pair<int,int> pii;

const ll mod = 998244353;


bool mark[maxn];
bool vis[maxn];
vector<int> G[maxn];
int n,m,t;
int flag;
void dfs(int s,int pre,ll& odd,ll& tot)
{
    if(!flag)
        return;

    vis[s]=1;
    mark[s]=1-pre;
    if(mark[s])
        odd++;
    tot++;

    for(int i=0;i<G[s].size();i++)
    {
        if(!vis[G[s][i]])
        {
            vis[G[s][i]]=1;
            dfs(G[s][i],mark[s],odd,tot);
        }
        else
        {
            if(mark[s]==mark[G[s][i]])
            {
                flag=0;
                return;
            }
        }
    }
}


ll QPower(ll x,ll n)
{
    ll res=1;
    while(n>0)
    {
        if(n&1)
            res=res*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        if(m==0)
        {
            cout<<QPower(3,n)<<endl;
            continue;
        }
        for(int i=1;i<=n;i++)
        {
            G[i].clear();
            vis[i]=mark[i]=0;//不能使用memset初始化,否则超时
        }
        flag=1;

        int a,b;
        ll ans=1,res=0,odd,tot;
        for(int i=1;i<=m;i++)
        {
            cin>>a>>b;
            G[a].push_back(b);
            G[b].push_back(a);
        }
        for(int i=1;i<=n;i++)
        {
            res=odd=tot=0;
            if(!vis[i])
            {
                mark[i]=vis[i]=1;
                if(G[i].empty())
                    res=3;
                else
                {
                    dfs(i,0,odd,tot);
                    if(!flag)//判断是否出现无法二染色的联通分量
                        break;
                    res=(QPower(2,odd)%mod+QPower(2,tot-odd)%mod)%mod;
                }
                ans=ans*res%mod;
            }
        }

        if(!flag)
            cout<<0<<endl;
        else
        {
            cout<<ans<<endl;
        }

    }
    return 0;
}

思路:

分析一下题目,其实挺简单的,如果一条边上两个节点上面的标号和是奇数,那么两个节点一定要是一个奇数加上一个偶数。由于只有1,2,3三个数在节点上标号,所以可以将问题转换成图的二染色问题,如果能对图进行二染色,那么就能进行标号,否则不能。

题目中奇数有两种1和3,偶数只有2,所以对图进行标号的种类为: 2 o d d 2^{odd} 2odd,其中odd为标注奇数的节点的个数。由于标注偶数的节点可以和标注奇数的节点互换,所以还要再加上 2 t o t − o d d 2^{tot-odd} 2totodd,其中tot是总共节点的个数。

如果出现只有一个节点,没有边的情况,那么这个节点有三种标号方法。

其中2次幂数可以使用快速幂来进行优化。

注意,此题是t组数据测试,而且数据范围较大。不要使用memset来进行初始化,否则超时

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值