Educational Codeforces Round 56 (Rated for Div. 2) D. Beautiful Graph(二分图判定+计数)

题意

给一个图,图上的点可以被染成权值为1,2,3

令边权=两个点的点权和,求令边权为奇数的所有方案数%998244353

思路来源

自己写的

题解

首先二分图判定一下,分奇偶层;

奇层染奇数,偶层染偶数;

或奇层染偶数,偶层染奇数。

对于每个连通分量,其方案数为(modpow(2,奇层点数,MOD)+modpow(2,偶层点数,MOD))%MOD

这个modpow是快速幂。

然后整个图的就是所有连通分量的乘积%MOD了。

心得

开始没注意到图不一定是连通图,WA了一发。

再后来e数组60W开小了,又WA一发。

再后来这个n总共是3e5,每次去memset所有,T了五六发……

所以应该就是for循环到n赋初值 这样遭遇T=300000 n=1 m=0的极限样例也不会爆了

或者每次用到哪个的时候才去初始化哪个,最后就是改成这样的

代码还是不规范啊……明明能O(均摊n),非要O(T·n),

改完之后2000msTLE变140msAC,真是令人窒息的操作

代码

#include <iostream>
#include <algorithm> 
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=3e5+10; 
const int mod=1e9+7;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pii pair<int,int> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%I64d",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
int cnt,head[maxn],color[maxn],shu;
int t,n,m,pos[maxn],neg[maxn],now;
struct edge
{
 int to,nex;
}e[maxn*2];
//可能很多连通分量 最后的答案是各连通分量贡献的乘积
//二分图判定一次 
void init(int n)
{
	for(int i=0;i<n;++i)
	color[i]=0,head[i]=-1;
	cnt=0;
	shu=1;
}
void add(int u,int v)
{
	e[cnt].to=v;
	e[cnt].nex=head[u];
	head[u]=cnt++;
}
ll modpow(ll x,ll n,ll mod)
{
	if(n==0)return 1;
	ll res=modpow(x,n/2,mod),ans=res*res;
	if(ans>=mod)ans%=mod;
	if(n&1)ans=ans*x;
	if(ans>=mod)ans%=mod;
	return ans;
}
bool judge(int u,int c)
{
	color[u]=c;
	if(c>0)pos[c]++;
	else
	{
		int p=-c;
		neg[p]++;
	}
	for(int i=head[u];~i;i=e[i].nex)
	{
		int v=e[i].to;
		if(color[v]==c)return 0;//相邻同号 
		if(color[v]==0&&!judge(v,-c))return 0;
	}
	return 1;
}
ll solve()
{
	ll ans=1;
	for(int i=0;i<n;++i)
	{
		if(color[i]==0)
		{
			pos[shu]=0;//memset会T!!!
			neg[shu]=0;//memset会T!!! 
			if(!judge(i,shu))return 0;
			shu++; //shu-1个连通分量 
		}
	}
	rep(i,1,shu-1)
	{
	 ll tmp1=modpow(2,pos[i],MOD);
	 ll tmp2=modpow(2,neg[i],MOD);
	 ll q=tmp1+tmp2;
	 if(q>=MOD)q%=MOD;
	 ans=ans*q;
	 if(ans>=MOD)ans%=MOD;
	}
	return ans;
}
int main()
{ 
  sci(t);
  while(t--)
  {
  	sci(n),sci(m);
  	init(n);
	rep(i,0,m-1)
	{
		int u,v;
		sci(u),sci(v);
		u--,v--;
		add(u,v);
		add(v,u);
	} 
	printf("%I64d\n",solve());
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/85021714