【UNR #2】UOJ拯救计划

UOJ小清新题表

题目内容

UOJ链接

题面太长了(其实是我懒得改LaTeX了)
一句话题意:
给出 (n) 个点和 (m) 条边,对其进行染色,共 (k) 种颜色,要求同一条边两点颜色不同,输出方案数(pmod 6)

数据范围

(1leq nleq 10^5,0leq mleq 2 imes 10^5,1leq kleq 10^4)

思路

水题解,他不香吗

由于本人并不会UOJ中的其他题,所以来水最简单的一道了

直接计算的话,答案为:

[sumlimits^k_{i=1}A^i_k imes x ]

其中(x)为用(i)种颜色的方案数,不过你可能惊喜的发现这个是个(NPC)问题。

所以为什么我要在一句话题意中把( ext{mod} 6)写上呢,因为当(igeq 3)的时候,答案肯定为0。

所以好像只需要讨论(i=1,2)即可。

  • (i=1)
    • (m=0),直接是一堆点,(ans=1)
    • (m ot=0),那么只能(ans=0)
  • (i=2)
    • (m=0),对于(n)个点都有(2)种颜色可选,(ans=k^2)
    • (m ot=0),设图中共有(tot)个联通块,(ans=C^2_k imes 2^{tot})。当然如果发现有一个联通块无法完成染色,答案就直接是(0)

然后其实(m=0)的时候直接答案就是(k^n)就行。

代码

#include <bits/stdc++.h>
#define int long long
#define Clean(a) memset(a,0,sizeof(a))
using namespace std;
const int maxn=5e5+10;
const int Mod=6;
int n,m,k;
int vis[maxn];

struct Edge{
    int from,to,w,nxt;
}e[maxn<<1];

inline int read(){
    int x=0,fopt=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')fopt=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        x=(x<<3)+(x<<1)+ch-48;
        ch=getchar();
    }
    return x*fopt;
}

int head[maxn],cnt;
inline void add(int u,int v){
    e[++cnt].from=u;
    e[cnt].to=v;
    e[cnt].nxt=head[u];
    head[u]=cnt;
}

inline int qpow(int x,int b){
    int ans=1,base=x;
    while(b){
        if(b&1)ans=ans*base%Mod;
        base=base*base%Mod;
        b>>=1;
    }
    return ans;
}

bool dfs(int u,int col){
    vis[u]=col;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(!vis[v]){
            if(!dfs(v,-col))return 0;
        }else if(vis[u]==vis[v])return 0;
        
    }
    return 1;
}

inline void Init(){
    cnt=0;
    Clean(e);
    Clean(head);
    Clean(vis);
}

signed main(){
    int T=read();
    while(T--){
        n=read();m=read();k=read();
        if(m==0){
            printf("%lld
",qpow(k,n));
            continue;
        }else{
            if(k==1){
                for(int i=1;i<=m;i++){
                    read();read();
                }
                puts("0");
                continue;
            }else{
                Init();
                for(int i=1;i<=m;i++){
                    int u=read(),v=read();
                    add(u,v);add(v,u);
                }
                int tot=0,flag=1;
                for(int i=1;i<=n;i++){
                    if(!vis[i]){
                        if(dfs(i,1))tot++;
                        else{
                            flag=0;break;
                        }
                    }
                }
                printf("%lld
",(k*(k-1)/2)%Mod*qpow(2,tot)*flag%Mod);
            }
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Midoria7/p/13507397.html