【JZOJ 省选模拟】人生(life)

题目

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);
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值