[UOJ UNR#2 UOJ拯救计划]

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

 

posted @ 2017-09-02 21:14  FallDream  阅读(200)  评论(0编辑  收藏  举报