题目
Description
Input
第一行一个正整数n。
第二行n个整数,其中第i个整数为1表示点i的颜色为黑色,为0表示点i的颜色为白色,为-1
则不确定。
Output
输出一行一个整数表示答案。
Sample Input
样例输入 1:
3
-1 0 1
样例输入 2:
5
-1 0 0 -1 1
样例输入 3:
10
0 0 1 1 -1 -1 1 0 1 0
Sample Output
样例输出 1:
6
样例输出 2:
2112
样例输出 3
142536119
Data Constraint
本题采取子任务捆绑测试。
Hint
思路
设end(i)表示以i结尾的合法路径条数
考虑一个DP:f[i][j][k][h]表示就前𝑖个点,有𝑗个白点和𝑘个黑点满足其𝑒𝑛𝑑为奇数,并且这𝑖个点的𝑒𝑛𝑑之和的奇偶性为ℎ的方案数
转移时枚举i+1的颜色,分类讨论
然后我们发现不用确切知道这j,k个点是哪些,因为我们只要保证有j,k个就行
于是:
然后我们发现一个重要性质
所以我们设f[i][0/1][0/1][h]表示前i个,是否有奇数的白色点,是否有奇数的黑色点,end和 奇偶性为h的方案数
讨论转移即可
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+77,mod=998244353;
ll f[N][2][2][2],_2[N];
int n;
int main()
{
freopen("life.in","r",stdin); freopen("life.out","w",stdout);
scanf("%d",&n);
// f[0][0][0][0]=1;
_2[0]=1;
for(int i=1; i<=n; i++) _2[i]=2*_2[i-1]%mod;
for(int i=1; i<=n; i++)
{
int x;
scanf("%d",&x);
if(i==1)
{
if(x!=0) f[i][0][1][1]=1;
if(x!=1) f[i][1][0][1]=1;
}
if(i!=1) for(int h=0; h<=1; h++)
{
if(x!=1)
{
// f[i][0][0][h]+=f[i-1][0][0][h]*0;
(f[i][1][0][h^1]+=(f[i-1][0][0][h]+f[i-1][1][0][h])*_2[i-1])%=mod;
// (f[i][1][0][h]+=)
(f[i][0][1][h]+=f[i-1][0][1][h]*_2[i-2])%=mod;
(f[i][1][1][h^1]+=(f[i-1][0][1][h]+f[i-1][1][1][h])*_2[i-2])%=mod;
(f[i][1][1][h]+=f[i-1][1][1][h]*_2[i-2])%=mod;
}
if(x!=0)
{
// f[i][0][0][h]+=*0;
(f[i][0][1][h^1]+=(f[i-1][0][0][h]+f[i-1][0][1][h])*_2[i-1])%=mod;
(f[i][1][0][h]+=f[i-1][1][0][h]*_2[i-2])%=mod;
(f[i][1][1][h^1]+=(f[i-1][1][0][h]+f[i-1][1][1][h])*_2[i-2])%=mod;
(f[i][1][1][h]+=f[i-1][1][1][h]*_2[i-2])%=mod;
}
}
}
printf("%lld",(f[n][0][0][1]+f[n][0][1][1]+f[n][1][0][1]+f[n][1][1][1])%mod);
}