题意:有\(n\)个点,\(m\)条边的无向图,可以给每个点赋点权\({1,2,3}\),使得每个点连的奇偶不同,问有多少种方案,答案对\(998244353\)取模.
题解:要使得每个点所连的奇偶不同,很明显是二分图染色,那么对于某一个联通块,我们可以对左边的点赋\(2\),右边的点赋\({1,3}\),那么左边的点没有选择,只有一种情况,而右边的点每个点可以有两种情况,如果右边的点数是\(k_2\),那么方案数就是\(2^{k_2}\),如果左边赋\({1,3}\)且点数为\(k_1\),右边赋\(2\),方案数就是\(2^{k_1}\),所以一个联通块的方案数就是\(2^{k_1}+2^{k_2}\).我们可以不考虑点权,直接dfs二分图染色,记录二分图两边的点数,再直接贡献给答案即可.
-
代码:
int t;
int n,m;
vector<int> v[N];
int color[N];
int g[N];
int cnt[N];
int ans; bool dfs(int x,int c){
color[x]=c; for(auto w:v[x]){
if(!color[w]){
if(!dfs(w,3-c)) return false;
}
else{
if(color[w]==c) return false;
}
}
cnt[c]++;
return true;
} int main() {
//ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
scanf("%d",&t);
g[0]=1; for(int i=1;i<=300010;++i){
g[i]=g[i-1]*2%mod;
} while(t--){
scanf("%d %d",&n,&m); ans=1; for(int i=1;i<=n;++i){
color[i]=0;
} for(int i=1;i<=m;++i){
int a,b;
scanf("%d %d",&a,&b);
v[a].pb(b);
v[b].pb(a);
} bool ok=true; for(int i=1;i<=n;++i){
if(!color[i]){
cnt[1]=cnt[2]=0;
if(!dfs(i,1)){
ok=false;
break;
}
else{
ans=(ll)ans*(g[cnt[1]]+g[cnt[2]])%mod;
}
}
} if(ok) printf("%d\n",ans);
else printf("0\n"); for(int i=1;i<=n;++i) v[i].clear(); } return 0;
}