大致题意:给你一个序列,数字有-1或者1到k构成。其中的-1需要用1到k中任意一个数字替代,现在定义一个坏序列的标准是把-1替代完毕后,没有长度大于1的奇回文串。问你在所有的替代方案中,最后能得到不是坏序列的方案数是多少。
这里的一个奇回文串,看似很复杂不知道应该怎么做,但是其实很容易发现,所有的奇回文串必定包含一个长度为3的回文串。换句话说,含有长度为3的回文串的就是坏序列。再进一步,发现长度为3的回文串,第一个字符和第三个字符是一样的。也就意味着,如果我们把原串按照奇偶取拆成两个串的话,只要其中有一个串有连续两个相同的字符,那么这个串就是一个坏序列,反之就是好序列。
继续分析,最后的答案就是奇数串好序列个数*偶数串好序列个数。那么,现在问题的关键就是怎么求这个好序列个数。我们考虑dp[i][0]表示长度为i的一串-1且两端夹着两个不相等的数字的好序列方案数。同理,dp[i][1]表示长度为i的一串-1且两端夹着两个相等的数字的好序列的方案数。那么,我们可以很简单的得到转移方程:
根据这个转移方程,我们就可以把序列按照已知的数字进行分段,把每一段的方案数乘起来就是我们最后的答案。最后要特殊处理一下两端为-1的情况。具体见代码:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define file(x) freopen(#x".in","r",stdin);
using namespace std;
const int N = 2e5 + 10;
const int mod = 998244353;
int a[N],b[N];
int n,k,l1,l2;
LL solve(int *a,int len)
{
if (len==1)
if (a[1]==-1) return k;
else return 1;
LL sam=1,dif=0,res=1;
int ls=a[1];
for(int i=2;i<=len;i++)
{
LL nxt_sam=dif*(k-1)%mod;
LL nxt_dif=(sam+(k-2)*dif%mod)%mod;
if (a[i]==-1) sam=nxt_sam,dif=nxt_dif;
else
{
if (ls==-1) res=res*(nxt_sam+nxt_dif*(k-1)%mod)%mod;
else res=res*(a[i]==ls?nxt_sam:nxt_dif)%mod;
ls=a[i]; sam=1; dif=0;
}
}
res=res*(sam+dif*(k-1)%mod)%mod;
if (ls==-1) return res*k%mod;
return res;
}
int main()
{
scc(n,k);
for(int i=1;i<=n;i++)
{
int x; sc(x);
if (i&1) a[++l1]=x;
else b[++l2]=x;
}
printf("%lld\n",solve(a,l1)*solve(b,l2)%mod);
}
/*
5 3
-1 -1 -1 -1 -1
6 5
-1 -1 -1 2 -1 -1
9 3
-1 -1 -1 -1 1 2 3 -1 -1
*/