这一题我的思路是设 fu,i 为 u 子树内颜色选取情况为 i 时方案数,并预处理 cani,j 为其中一部分子树颜色选取状况为 i,另一部分子树颜色选取状况为 j 时是否满足要求,过了样例结果 WA 0pts。
附上代码,求纠正思路(或代码)
#include <algorithm>
#include <cstdio>
#define mod 1000000007
int _cnt, head[100001];
struct edge{
int v, nxt;
}e[200001];
inline void addedge(int u, int v){
e[++ _cnt] = {v, head[u]};
head[u] = _cnt;
}
using namespace std;
int t, n, K, a[6][6], f[100001][1 << 5][2], ans;
bool can[1 << 5][1 << 5];
void init(){
_cnt = 0;
for (int i = 1;i <= n;i ++) head[i] = -1;
}
int tmp[1 << 5];
void dp(int u){
if (head[u] == -1){
for (int i = 1;i <= K;i ++) f[u][1 << i - 1][0] = 1;
return;
}
int p = 1, i = head[u];
int v = e[i].v;dp(v);
for (int j = 0;j < (1 << K);j ++) f[u][j][p] = f[v][j][0];
for (i = e[i].nxt;i != -1;i = e[i].nxt){
p ^= 1;
v = e[i].v;dp(v);
for (int j = 0;j < (1 << K);j ++) f[u][j][p] = 0;
for (int j = 0;j < (1 << K);j ++){
for (int k = 0;k < (1 << K);k ++){
if (can[j][k]) f[u][j | k][p] = (f[u][j | k][p] + 1ll * f[u][j][p ^ 1] * f[v][k][0] % mod) % mod;
}
}
}
if (p) for (int j = 0;j < (1 << K);j ++) swap(f[u][j][0], f[u][j][1]);
}
int main(){
scanf("%d", &t);
while (t --){
scanf("%d%d", &n, &K), init(), ans = 0;
for (int i = 1;i <= K;i ++){
for (int j = 1;j <= K;j ++) scanf("%d", &a[i][j]);
}
for (int u, v = 2;v <= n;v ++) scanf("%d", &u), addedge(u, v);
for (int i = 0;i < (1 << K);i ++){
for (int j = 0;j < (1 << K);j ++){
can[i][j] = 1;
int t = 0;
for (int k = 1;k <= K;k ++){
if (i >> (k - 1) & 1){
for (int l = 1;l <= K;l ++){
if (j >> (l - 1) & 1){
if (t == 0) t = a[k][l];
else if (t != a[k][l]) can[i][j] = 0;
if (t != a[l][k]) can[i][j] = 0;
}
}
}
}
}
}
dp(1);
for (int i = 0;i < (1 << K);i ++) ans = (ans + f[1][i][0]) % mod;
printf("%d\n", ans);
}
}