(n) 和 (k) 和 (n) 个数的序列 (a)。把 (a) 中的 (-1) 替换成 ([1,k]) 之间的整数。求使 (a) 中不存在长度为奇数的回文串的方案数。
数据范围:(2le n,kle 2cdot 10^5),(a_i=-1{ m~or~}a_iin[1,k])。
题目限制即不能有 (a_i=a_{i-2})。
令 (b_i=a_{2i},c_i=a_{2i-1})。
答案为序列 (b) 和 (c) 填成相邻两数不等的方案数积。
如填 (x,-1,-1,...,-1,y) 这段 (i) 个 (-1) 使相邻两数不等:
令 (f_i) 表示 (x=y) 的填法方案数,(g_i) 表示 (x ot=y) 的填法方案数。
[f_i=
egin{cases}
0&(i=0)\
g_{i-1}(k-1)&{
m else}\
end{cases}\\
g_i=
egin{cases}
1&(i=0)\
g_{i-1}(k-2)+f_{i-1}&{
m else}\
end{cases}
]
最后把每段 (-1) 的答案乘起来就是填 (b,c) 的方案数。
边界的处理具体看代码。
- 代码
#include <bits/stdc++.h>
using namespace std;
//Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair(a,b)
#define x first
#define y second
#define b(a) a.begin()
#define e(a) a.end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
//Data
const int N=2e5;
const int mod=998244353;
int n,k,a[N+7];
//DP
int f[2][(N<<1)+7];
int bb,b[(N>>1)+7],cc,c[(N>>1)+7];
void Pre(){
f[0][0]=0,f[1][0]=1;
for(int i=1;i<=(n>>1)+1;i++){
f[0][i]=(ll)f[1][i-1]*(k-1)%mod;
f[1][i]=((ll)f[1][i-1]*(k-2)%mod+f[0][i-1])%mod;
}
}
int DP(int cnt,int s[]){
int len=0,lst=0,res=1;
for(int i=1;i<=cnt;i++){
if(s[i]==-1) len++;
else {
if(len){
if(!lst) res=(ll(k-1)*f[1][len-1]+f[0][len-1])%mod*res%mod;
else if(lst==s[i]) res=(ll)f[0][len]*res%mod;
else res=(ll)f[1][len]*res%mod;
}
len=0,lst=s[i];
}
}
if(len){
if(!lst){
if(len==1) res=k;
else res=(ll(k-1)*f[1][len-2]+f[0][len-2])*k%mod*res%mod;
} else res=(ll(k-1)*f[1][len-1]+f[0][len-1])%mod*res%mod;
}
return res;
}
//Main
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(~a[i]&&i-2>=1&&a[i]==a[i-2]) return puts("0"),0;
if(i&1) c[++cc]=a[i];
else b[++bb]=a[i];
}
Pre();
printf("%d
",(ll)DP(cc,c)*DP(bb,b)%mod);
return 0;
}
祝大家学习愉快!