CF979E 题解
本题采用 DP 套 DP。
首先,我们考虑怎么在确定所有点颜色且确定所有连边的情况下算方案数。不难发现可以采用 DAG 上 DP。
令 $g_i$ 表示以 $i$ 开头的路径数量,那么他可以从所有颜色和他不同的点转移过来。转移顺序的话按照 DAG 的反图上的拓扑顺序来。
再考虑外层 DP。令 $f_{i,j,k,t}$ 表示以 $i$ 到 $n$ 中,总路径条数的为奇数/偶数($j=0$ 为奇数,$j=1$ 为偶数),存在/不存在 $g_x \equiv 1 \pmod{2}$ 的黑点($k=0$ 表示不存在,$k=1$ 则反之),存在/不存在 $g_x \equiv 1 \pmod{2}$ 为奇数的白点($t=0$ 表示不存在,$t=1$ 则反之)的方案数。
转移的话就很简单,我们枚举可以选的颜色,然后挑选一个其它颜色且 $g_x \equiv 1 \pmod{2}$ 的点用来协调整奇偶性,其它点可以有选/不选两种方案。若没有这样一个点,那么当前点开头路径数的奇偶性只能为奇数(注意当前点本身也算一条路径)。
#include <bits/stdc++.h>
#define L(i, a, b) for(int i = a; i <= b; i++)
#define R(i, a, b) for(int i = a; i >= b; i--)
using namespace std;
const int N = 50 + 10, mod = 1e9 + 7;
int n, p, ans, c[N], pw[N] = {1}, f[N][2][2][2];
int main(){
scanf("%d%d", &n, &p);
L(i, 1, n) scanf("%d", &c[i]);
L(i, 1, n) pw[i] = (pw[i - 1] << 1) % mod;
f[n + 1][0][0][0] = 1;
R(i, n, 1) L(j, 0, 1) L(k, 0, 1) L(t, 0, 1){
if(!f[i + 1][j][k][t]) continue;
if(c[i] != 1){
if(t){
(f[i][j][k][t] += 1ll * pw[n - i - 1] * f[i + 1][j][k][t] % mod) %= mod;
(f[i][j ^ 1][1][t] += 1ll * pw[n - i - 1] * f[i + 1][j][k][t] % mod) %= mod;
}
else (f[i][j ^ 1][1][t] += 1ll * pw[n - i] * f[i + 1][j][k][t] % mod) %= mod;
}
if(c[i] != 0){
if(k){
(f[i][j][k][t] += 1ll * pw[n - i - 1] * f[i + 1][j][k][t] % mod) %= mod;
(f[i][j ^ 1][k][1] += 1ll * pw[n - i - 1] * f[i + 1][j][k][t] % mod) %= mod;
}
else (f[i][j ^ 1][k][1] += 1ll * pw[n - i] * f[i + 1][j][k][t] % mod) %= mod;
}
}
L(k, 0, 1) L(t, 0, 1) (ans += f[1][p][k][t]) %= mod;
printf("%d\n", ans);
return 0;
}