【NOIP2013模拟9.29】Mixing Chemicals
一道组合计数的题目。
然后我想了两个小时,没想出来,太弱了额额...
首先我们输入的东西连边,然后,我们会得到一颗环套树.
那么我们现在就把问题转化为如何给这棵环套树K染色,使相邻节点颜色不同.
很显然,如果一个节点不在任何一个简单环里,那么他对答案的方案数贡献显然就是\((k-1)\).
而对于环,我们则另开讨论。
那么令\(f[i]\)表示当环的大小为\(i\)时,合法方案数.
那么显然,\(f[1]=k,f[2]=k*(k-1),f[3]=k*(k-1)*(k-2)\).
当\(i\ge 3\)时,我们就知道,有\[f[i]=f[i-1]*(k-2)+f[i-2]*(k-1)\]
意思就是,讨论一下\(i\)左右两个点的颜色是否相同,如果相同,那么等价于在\(i-2\)大小的环里的方案数*当前有\((k-1)\)种方案,另一种类似。
然后就可以愉快的DP一下,因为n特别小,所以怎么搞环都可以.
#include <iostream>
#include <cstdio>
#include <cstring>
#define F(i, a, b) for (int i = a; i <= b; i ++)
#define mem(a, b) memset(a, b, sizeof a)
const int N = 1e2 + 10, Mo = 1e9 + 7;
int T, n, k, tot, ans, p, total, c[N], f[N], vis[N], fa[N], bz[N];
using namespace std;
int main() {
for (scanf("%d", &T); T --; ) {
scanf("%d %d", &n, &k), total = n, mem(vis, 0);
F(i, 0, n - 1) scanf("%d", &fa[i]);
f[1] = k, f[2] = (1LL * k * (k - 1)) % Mo, f[3] = ((1LL * k * (k - 1) % Mo)* (k - 2)) % Mo, ans = 1;
F(i, 4, n) f[i] = ((1LL * f[i - 1] * (k - 2) % Mo)+ (1LL * f[i - 2] * (k - 1)) % Mo) % Mo;
F(i, 0, n - 1)
if (!vis[i]) {
for (p = i, tot = 0, mem(bz, 0); !bz[p]; bz[p] = 1, p = fa[p], tot ++);
if (p ^ i) continue;
for (p = i, mem(bz, 0); !bz[p]; bz[p] = vis[p] = 1, p = fa[p]);
total -= tot, ans = (1LL * ans * f[tot]) % Mo;
}
F(i, 1, total)
ans = (1LL * ans * (k - 1)) % Mo;
printf("%d\n", ans);
}
}