来自FallDream的博客,未经允许,请勿转载,谢谢。
传送门
感觉这题有点神...
模数是6比较奇怪,考虑计算答案的式子。
Ans=$\sum_{i=1}^{k} P(k,i)*ans(i)$ ans(i)表示恰好用i种颜色的方案数。
发现i<=2时候才有贡献
i=1的时候,只有m=0才有贡献,否则没有
i=2的时候,判断图是否是二分图,是的话答案就是2^(联通块个数)
#include<iostream> #include<cstring> #include<cstdio> #define MN 100000 using namespace std; inline int read() { int x=0;char ch=getchar(); while(ch<‘0‘||ch>‘9‘) ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar(); return x; } int sum; inline int pow(int x,int k) { for(sum=1;k;k>>=1,x=1LL*x*x%6) if(k&1) sum=1LL*sum*x%6; return sum; } int head[MN+5],vis[MN+5],cas,cnt,n,m,k,ans,col[MN+5]; struct edge{int to,next;}e[MN*4+5]; inline void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; } void Solve(int x) { vis[x]=cas; for(int i=head[x];i;i=e[i].next) if(vis[e[i].to]!=cas) col[e[i].to]=col[x]^1,Solve(e[i].to); else if(col[e[i].to]==col[x]) ans=0; } int main() { for(cas=read();cas;--cas) { n=read();m=read();k=read(); memset(head,0,sizeof(head));cnt=0;ans=1; for(int i=1;i<=m;++i) ins(read(),read()); if(!m) {printf("%d\n",pow(k,n));continue;} if(k==1||k%3!=2) {puts("0");continue;} for(int i=1;i<=n;++i) if(vis[i]!=cas) col[i]=0,Solve(i),ans=ans*2%6; printf("%d\n",ans); } return 0; }
时间: 2024-10-13 08:56:27