题目链接
解题思路
首先,我们可得答案
a
n
s
=
∑
i
=
1
k
A
k
i
∗
[
恰
好
选
择
i
种
颜
色
的
本
质
不
同
排
列
的
方
案
数
]
ans=\sum_{i=1}^kA_k^i*[恰好选择i种颜色的本质不同排列的方案数]
ans=i=1∑kAki∗[恰好选择i种颜色的本质不同排列的方案数]
这是个NP完全问题
emmm那怎么办?
我们看题目!
这个模数不太正常!
我们都知道
A
k
i
=
k
(
k
−
1
)
(
k
−
2
)
.
.
.
(
k
−
i
+
1
)
A_k^i=k(k-1)(k-2)...(k-i+1)
Aki=k(k−1)(k−2)...(k−i+1)
另外,两个连续整数相乘一定是2倍数,三个连续整数相乘一定是3的倍数,也一定是6的倍数
ok。如果
i
≥
3
i\geq3
i≥3,则肯定有
6
∣
A
k
i
6|A_k^i
6∣Aki。所以不用考虑
所以我们只要考虑当
i
=
1
i=1
i=1和当
i
=
2
i=2
i=2时对答案的贡献
我们先考虑
m
=
0
m=0
m=0这一特殊情况。在这种情况下,我们的方案数就为
k
n
k^{n}
kn了.
然后我们考虑
m
!
=
0
m!=0
m!=0的情况。在这种情况下,
当
i
=
1
i=1
i=1时,方案数为零,不用考虑
当
i
=
2
i=2
i=2时,要用两只颜色对图染色,其实就相当于二分图。如果该图不是二分图,显然无法染色,方案数为零。否则,方案数为
C
k
2
2
连
通
块
个
数
C_k^22^{连通块个数}
Ck22连通块个数
=
k
(
k
−
1
)
2
连
通
块
个
数
−
1
=k(k-1)2^{连通块个数-1}
=k(k−1)2连通块个数−1
只要统计出连通块个数即可
完美
详细代码
#define USEFASTERREAD 1
#define rg register
#define inl inline
#define DEBUG printf("[Passing [%s] in line %d.]\n", __func__, __LINE__)
#define putline putchar('\n')
#define putsp putchar(' ')
#define Rep(a, s, t) for(rg int a = s; a <= t; a++)
#define Repdown(a, t, s) for(rg int a = t; a >= s; a--)
typedef long long ll;
#include<cstdio>
#define rs freopen("test.in", "r", stdin), freopen("test.out", "w", stdout)
#if USEFASTERREAD
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
#endif
struct IO
{
void RS() {rs;}
template<typename T> inline IO r(T& x)const
{
x = 0; T f = 1; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');
x *= f; return *this;
}
template<typename T> inline IO w(T x)const
{
if(x < 0) {putchar('-'); x = -x;}
if(x >= 10) w(x / 10);
putchar(x % 10 + '0'); return *this;
}
template<typename T> inline IO wl(const T& x)const {w(x), putline; return *this;}
template<typename T> inline IO ws(const T& x)const {w(x), putsp; return *this;}
inline IO l() {putline; return *this;}
inline IO s() {putline; return *this;}
}io;
template<typename T> inline T Max(const T& x, const T& y) {return y < x ? x : y;}
template<typename T> inline T Min(const T& x, const T& y) {return y < x ? y : x;}
template<typename T> inline void Swap(T& x, T& y) {T tmp = x; x = y; y = tmp;}
#include<cstring>
const int MAXN = 100005, MAXM = 200005;
const int MO = 6;
int T;
int n, m, k;
struct Edge
{
int v, nxt;
}e[MAXM * 2];
int head[MAXN], cnt;
void addedge(int u, int v)
{
e[++cnt].v = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int qpow(int a, int n)
{
int res = 1;
while(n)
{
if(n & 1) res = (res * a) % MO;
a = (a * a) % MO;
n >>= 1;
}
return res;
}
int vis[MAXN], col[MAXN];
bool Dfs(int u)
{
vis[u] = 1;
for(rg int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v;
if(!vis[v])
{
col[v] = col[u] ^ 1;
if(!Dfs(v)) return false;
}
else if(col[u] == col[v]) return false;
}
return true;
}
int main()
{
//io.RS();
io.r(T);
while(T--)
{
cnt = 0;
memset(e, 0, sizeof e);
memset(head, 0, sizeof head);
io.r(n).r(m).r(k);
for(rg int i = 1; i <= m; i++)
{
int u, v;
io.r(u).r(v);
addedge(u, v);
addedge(v, u);
}
if(m == 0)
{
io.wl(qpow(k, n));
continue;
}
//i == 2
memset(vis, 0, sizeof vis);
memset(col, 0, sizeof vis);
int ans = 0;//联通块个数
for(rg int i = 1; i <= n; i++)
if(!vis[i])
{
ans++;
col[i] = 0;
if(!Dfs(i)) {io.wl(0); goto non_ans;}
}
io.wl((qpow(2,ans-1) * k) % MO * (k - 1) % MO);
non_ans:;
}
return 0;
}