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 << '
';
}
原文地址:https://www.cnblogs.com/s-r-f/p/13599466.html