Description
给定一个长度为 \(n\) 的数组,其中有些位置未定(可在 \([1,k]\) 中任意取值),问有多少种填数的方案可以使得数组中不存在长度为奇数的回文子串。
Solution
即不存在长度为 \(3\) 的回文串
即对任意 \(i\) 有 \(a_i \neq a_{i+2}\)
考虑分奇偶位处理,方案数相乘
于是转化为相邻两位不相同的方案数
考虑对于每一段连续的 \(-1\) 分别处理
设 \(f[i][0]\) 表示长度为 \(i\) 的 \(-1\) 段的左边和右边的元素相同的方案数,\(f[i][1]\) 为不同,则有
\[f[i][0]=(k-1) \cdot f[i-1][1] \\
f[i][1]=(k-2)\cdot f[i-1][1] +f[i-1][0]
\]
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
const int mod = 998244353;
const int dbg = 0;
int n,k,a[N],f[N][2],p[N],cnt,b[N];
int qpow(int p,int q)
{
return (q&1 ? p : 1) * (q? qpow(p*p%mod,q/2) : 1) % mod;
}
void presolve()
{
f[0][0]=0; f[0][1]=1;
for(int i=1;i<=n+1;i++)
{
f[i][0]=(k-1)*f[i-1][1];
f[i][1]=(k-2)*f[i-1][1]+f[i-1][0];
f[i][0]%=mod;
f[i][1]%=mod;
}
}
int solver(int n,int *a)
{
memset(p,0,sizeof p);
cnt=0;
for(int i=1;i<=n;i++) if(a[i]!=-1) p[++cnt]=i;
a[0]=-2;
a[n+1]=-2;
p[++cnt]=n+1;
if(dbg) for(int i=0;i<=2;i++)
{
cout<<"i="<<i<<" f[i][?]="<<f[i][0]<<","<<f[i][1]<<endl;
}
int ans=1;
for(int i=1;i<=cnt;i++)
{
int len=p[i]-p[i-1]-1;
if(dbg) cout<<len<<",";
if(len>0)
{
if(dbg) cout<<"<"<<p[i-1]<<","<<p[i]<<"> ";
if(a[p[i]]==-2 && a[p[i-1]]==-2) ans*=k*qpow(k-1,len-1)%mod, ans%=mod;
else if(a[p[i]]==-2 || a[p[i-1]]==-2) ans*=qpow(k-1,len), ans%=mod;
else if(a[p[i]]==a[p[i-1]]) ans*=f[len][0], ans%=mod;
else ans*=f[len][1], ans%=mod;
}
}
return ans;
}
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<n-1;i++) if(a[i]!=-1 && a[i]==a[i+2])
{
cout<<0<<endl;
return 0;
}
presolve();
int len1=0,len2=0;
for(int i=1;i<=n;i+=2) b[++len1]=a[i];
int ans1=solver(len1,b);
memset(b,0,sizeof b);
for(int i=2;i<=n;i+=2) b[++len2]=a[i];
int ans2=solver(len2,b);
if(dbg) cout<<ans1<<":"<<ans2<<endl;
cout<<ans1*ans2%mod<<endl;
}