LOJ#6497. 「雅礼集训 2018 Day1」图 题解
考虑 \(dp_{i,a,b,0/1}\) 表示当前DP到第i个,目前有a个黑色的奇数点,b个白色的计数点的方案数,转移直接暴力即可。
可以发现状态里的a/b
的值实际上没意义,如果没有,那么显然当前点必然是奇数;如果有,那么就是 \(\frac{1}{2}\) 的情况用偶数转移, \(\frac{1}{2}\) 的情况用奇数转移即可.
\(\Theta(n).\)
代码:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 200005,P = 998244353;
inline void upd(int &x,int v){ x = (x+v >= P) ? (x+v-P) : (x+v); }
int f[N][2][2][2],n,need,a[N],pw[N],ans;
int main(){
int i,j,k,t,v;
ios::sync_with_stdio(0);
cin >> n >> need;
for (pw[0] = i = 1; i <= n; ++i) cin >> a[i],pw[i] = pw[i-1] * 2ll % P;
if (a[1] ^ 1) f[1][1][0][1] = 1; if (a[1]) f[1][0][1][1] = 1;
for (i = 1; i < n; ++i)
for (j = 0; j <= 1; ++j)
for (k = 0; k <= 1; ++k)
for (t = 0; t <= 1; ++t) if (v = f[i][j][k][t]){
if (a[i+1] ^ 1){
if (k) upd(f[i+1][1][k][t^1],(LL)v * pw[i-1] % P),upd(f[i+1][j][k][t],(LL)v * pw[i-1] % P);
else upd(f[i+1][1][k][t^1],(LL)v * pw[i] % P);
}
if (a[i+1]){
if (j) upd(f[i+1][j][1][t^1],(LL)v * pw[i-1] % P),upd(f[i+1][j][k][t],(LL)v * pw[i-1] % P);
else upd(f[i+1][j][1][t^1],(LL)v * pw[i] % P);
}
}
upd(ans,f[n][0][0][need]),upd(ans,f[n][0][1][need]);
upd(ans,f[n][1][0][need]),upd(ans,f[n][1][1][need]);
cout << ans << '\n';
}