cf 1093d 二分图染色 + 计数 memset会T!!!!!!

题意:

n个点m条边组成的无向图,边没有权值。现在想给点赋权值,每个点可以赋值1、2、3,每条边连接的两个点的权值和为奇数,问给点赋权值的方案数。

题解:

1.每条边连接的两个点的权值和为奇数就是每条边连接的两个点的权值奇偶性不同,那么用染色法判定是否可以赋值。若无法做到相连的两个点权值奇偶性不同,那么就输出0。

2.这个图不一定是连通图,需要将每个连通子块的方案数相乘

3.连通子块的方案数求法:染色后一部分点为0表示偶数,1表示奇数。统计完成后得到num[0]个0和num[1]个1,因为奇数有1和3两个可能,而偶数只有2这一个可能,所以得到方案数为2^num[1]。将每个点的权值取反得到num[1]个0和num[0]个1,又得到方案数为2^num[0]。故连通子块的方案数为2^num[0]+2^num[1]

4.本来以为完成前三步就大功告成了,结果T了两发,搜了题解才发现memset比for循环慢!!!!!!

#include<bits/stdc++.h>
using namespace std;
#define N 300005
#define mod 998244353
vector <int> edge[N] ; 
int n , m ;
bool node[N] ;
bool vis[N] ;
bool flag ;
int num[2] ;
long long cnt[N] ;
void dfs(int u)
{
	int v ;
	int i , j ;
	num[node[u]] ++ ;
	vis[u] = 1 ;
	if(!flag)
	   return ;
	for(i = 0 ; i < edge[u].size() ; i ++)
    {
    	v = edge[u][i] ;
    	if(vis[v])
    	{
    	  if(node[u] != node[v])
    	    continue ;
		  else
		  {
		  	flag = 0 ;	
		  	return ;
		  }		    
		}
    	node[v] = 1 - node[u] ;
    	dfs(v) ;
	}
}
void init()
{
	int i ;
	cnt[0] = 1 ; 
	for(i = 1 ; i <= N - 5 ; i ++)
    	cnt[i] = (cnt[i - 1] * 2) % mod ;
}
long long cal()
{
	int i ;
    long long ans = 0 ;
	ans += cnt[num[0]] ;
	ans %= mod ;
	ans += cnt[num[1]] ;
	ans %= mod ;
	return ans ;
}
int main()
{
   int t ;
   int i , j ;
   int u , v ;
   long long sum ;
   init() ;
   scanf("%d" , &t) ;
   while(t --)
   {
   	 scanf("%d%d" , &n , &m) ;
   	 for(i = 1 ; i <= n ; i ++)
   	 {
   	   edge[i].clear() ;
	   vis[i] = 0 ;	
	 }
	 for(i = 0 ; i < m ; i ++)
   	 {
   	   scanf("%d%d" , &u , &v) ;
       edge[u].push_back(v) ;
	   edge[v].push_back(u) ;	
	 }
	 sum = 1 ;
	 flag = 1 ;
	 for(i = 1 ; i <= n ; i ++)
	 {
	   if(vis[i])
	      continue ;
       num[0] = num[1] = 0 ;
	   node[i] = 0 ;
	   dfs(i) ;	
	   sum = (sum * (cal())) % mod ;
	 }
	 if(!flag) 
     	printf("0\n") ;
	 else
     	printf("%lld\n" , sum) ;  
   }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值