题目大意
有一个(n)个点(m)条边的无向图。
要给每个点安排(k)种颜色中的一种,使任意两个相邻的点颜色不同。不一定要用上全部(k)种颜色,每种颜色可以用多次。
问不同的方案数模6,两种方案不同当且仅当存在一个点的颜色不同。
(nleq 10^5,mleq2 imes 10^5,kleq 10^4)。
一行题解
模6=>(forall xin Z,x>2,x!space modspace 6=0)=>只用算恰有1种颜色和2种颜色时
题解
(k)种颜色不一定要全部用上,可以考虑分别算出恰好用了(1~k)种颜色的方案数。
对于一种合法方案,交换两种不同的颜色染色的所有点后,这个方案还是合法的。所以恰好用了(x)种颜色的方案数是(x!)的倍数。
答案要模6,当(x>2)时(x!)是6的倍数,模6都是0,不用考虑。
只用考虑(x=1,x=2)的方案数。
(x=1)时,没有边时有1种方案,否则有0种。
(x=2)时,如果整张图中存在奇环,就有0种方案;否则有(2^{连通块数})种。
代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define LL long long
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 100007
#define maxm 400007
#define maxk 10007
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
char ch[20];int f=0;
if(!x){putchar('0'),putchar('
');return;}
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('
');
}
int n,m,K,fir[maxn],nxt[maxm],v[maxm],col[maxn],cnte,yes;
void ade(int u1,int v1){v[cnte]=v1,nxt[cnte]=fir[u1],fir[u1]=cnte++;}
void check(int u)
{
view(u,k)
{
if(col[v[k]]!=-1&&col[v[k]]==col[u]){yes=0;}
if(col[v[k]]==-1)col[v[k]]=col[u]^1,check(v[k]);
if(!yes)return;
}
}
int main()
{
int t=read();
while(t--)
{
n=read(),m=read(),K=read();int ans1=0,ans2=0;
rep(i,1,n)col[i]=fir[i]=-1;cnte=0;
rep(i,1,m){int x=read(),y=read();ade(x,y),ade(y,x);}
if(K>=1)ans1=m?0:K%6;
if(K>=2)
{
ans2=(LL)K*((LL)K-1ll)/2ll%6ll;yes=1;int p=1;
rep(i,1,n)if(col[i]==-1){col[i]=0,check(i),(p*=2)%=6;if(!yes)break;}
if(!yes)p=0;
if(!m)(p+=4)%=6;
(ans2*=p)%=6;
}
write((ans1+ans2)%6);
}
return (~(0-0)+1);
}
一些感想
模数!