求助
查看原帖
求助
477443
vegetable_kingGallium楼主2022/4/10 21:40

这一题我的思路是设 fu,if_{u, i}uu 子树内颜色选取情况为 ii 时方案数,并预处理 cani,jcan_{i, j} 为其中一部分子树颜色选取状况为 ii,另一部分子树颜色选取状况为 jj 时是否满足要求,过了样例结果 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);
	}
}
2022/4/10 21:40
加载中...