1. 程式人生 > >Educational Codeforces Round 56 (Rated for Div. 2) D. Beautiful Graph(二分圖判定+計數)

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