[組合] UOJ#308. 【UNR #2】UOJ拯救計劃
阿新 • • 發佈:2019-01-06
題意
給定一張n個點m條邊的無向圖,給圖的所有頂點染色,使得對於任意一條邊,兩端的顏色不同。有K種顏色可用。
求染色的方案數模6的值。
題解
挺簡單的題目,但是做的時候就沒想到……我好菜啊……
就是一個經典的貌似是NPC的問題,然後只需要輸出答案%6,使問題特殊化。
哪裡特殊了呢?
我們這樣考慮答案:
我們知道排列數
相信大家小學的時候都學過:任意兩個連續整數乘積一定有2這個約數,任意三個連續整數乘積一定有3這個約數。
這樣就簡單了,當
所以我們只需要考慮用1種顏色和2種顏色即可。
然後隨便亂搞一下就行了。
要注意
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long LL;
using namespace std;
const int maxn=1000005,maxe=4000005;
int Q,n,m,K,c[maxn],fa[maxn],res,cnt;
bool vis[maxn];
int fir[maxn],nxt[maxe],son[maxe],tot;
void add(int x,int y){
son[++tot]=y; nxt[tot]=fir[x]; fir[x]=tot;
}
int getfa(int x){ return fa[x]==x?x:fa[x]=getfa(fa[x]); }
void merge(int x,int y){
x=getfa(x); y=getfa(y);
if(x!=y) fa[x]=y;
}
void dfs(int x,int k){
vis[x]=true; c[x]=k;
for(int j=fir[x];j;j=nxt[j]){
if(!vis[son[j]]) dfs(son[j],k^1 );
else if(c[son[j]]!=(k^1)) res=0;
}
}
int main(){
freopen("uoj308.in","r",stdin);
freopen("uoj308.out","w",stdout);
scanf("%d",&Q);
while(Q--){
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<=n;i++) fa[i]=i;
memset(fir,0,sizeof(fir)); tot=0;
for(int i=1;i<=m;i++){
int x,y; scanf("%d%d",&x,&y);
add(x,y); add(y,x); merge(x,y);
}
if(m==0){
res=1; for(int i=1;i<=n-1;i++) res=(res*2)%6; res=(res-1+6)%6;
printf("%d\n",(K%6+(K%6)*(K-1)%6*res%6)%6);
} else{
for(int i=1;i<=n;i++) c[i]=-1;
memset(vis,0,sizeof(vis));
res=1; cnt=0;
for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0), cnt+=1;
for(int i=1;i<=cnt-1;i++) res=(res*2)%6;
printf("%d\n",res*(K%6)*(K-1)%6);
}
}
return 0;
}