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