Educational Codeforces Round 62 (Rated for Div. 2) E

题意

如果一个数组中有 > 1 >1 >1的奇数回文串就是 b a d bad bad.
数组中 − 1 -1 1的部分要求被替换成 1 − k 1-k 1k的数字,最后得到的不 b a d bad bad的数组有多少种

题解

如果能保证最小的奇数回文串不存在,就不会存在更大,最小的是 3 3 3
保证 a [ i ] ! = a [ i − 2 ] a[i]!=a[i-2] a[i]!=a[i2]
我们可以发现分奇偶讨论。

每一部分都是 − 1 − 1 − 1 − 1 X − 1 − 1 − 1 − 1 Y − 1 − 1 -1 -1 -1 -1\quad X\quad -1 -1 -1 -1 \quad Y\quad -1-1 1111X1111Y11

对于一个 a − 1 − 1 − 1 − 1 b a\quad -1 -1 -1 -1 \quad b a1111b的片段, a 、 b a、b ab相同与否得到的答案不一样。
可以用 d p dp dp求解。 d p [ i ] [ j ] dp[i][j] dp[i][j] j = 0 j=0 j=0表示与左右不同, j = 1 j=1 j=1表示与左不同, j = 2 j=2 j=2表示与右不同。
对于左右不同的情况,转移是:
d p [ i ] [ 0 ] = d p [ i − 1 ] [ 1 ] ∗ ( k − 2 ) + d p [ i − 1 ] [ 2 ] ∗ ( k − 2 ) + d p [ i − 1 ] [ 0 ] ∗ ( k − 3 ) dp[i][0]=dp[i-1][1]*(k-2)+dp[i-1][2]*(k-2)+dp[i-1][0]*(k-3) dp[i][0]=dp[i1][1](k2)+dp[i1][2](k2)+dp[i1][0](k3)
d p [ i ] [ 1 ] = d p [ i − 1 ] [ 2 ] + d p [ i − 1 ] [ 0 ] dp[i][1]=dp[i-1][2]+dp[i-1][0] dp[i][1]=dp[i1][2]+dp[i1][0]
d p [ i ] [ 2 ] = d p [ i − 1 ] [ 1 ] + d p [ i − 1 ] [ 0 ] dp[i][2]=dp[i-1][1]+dp[i-1][0] dp[i][2]=dp[i1][1]+dp[i1][0]
答案为 d p [ l e n ] [ 1 ] + d p [ l e n ] [ 0 ] dp[len][1]+dp[len][0] dp[len][1]+dp[len][0]

左右相同的时候比较简单,就不阐述了。
答案为 d p [ l e n ] [ 1 ] dp[len][1] dp[len][1]

我们再分别计算片段,开头可以看做是左右相同的,但是这一片段答案是 d p [ i ] [ 0 ] + d p [ i ] [ 1 ] dp[i][0]+dp[i][1] dp[i][0]+dp[i][1],因为最左边没有其他元素。

如果片段中的 − 1 -1 1 0 0 0呢,那么:
左右不同,则是 d p 1 [ 0 ] [ 0 ] + d p 1 [ 0 ] [ 1 ] dp1[0][0]+dp1[0][1] dp1[0][0]+dp1[0][1],答案为 1 1 1
左右相同,则是 d p 2 [ 0 ] [ 0 ] dp2[0][0] dp2[0][0],答案为 0 0 0
符合要求。

#include<bits/stdc++.h>
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define sf(x) scanf("%d",&x)
typedef long long ll;
using namespace std;

const ll mod = 998244353;
const int maxn = 2e5+500;

int n,k;
ll dp1[maxn][3],dp2[maxn][2];
vector<int>odd,even;
int A[maxn];

int main(){
    cin>>n>>k;
    dp1[0][1]=1;
    dp1[0][0]=dp1[0][2]=0;
    for(int i=1;i<=200050;i++){
        dp1[i][0]=(dp1[i-1][1]*(k-2))%mod;
        dp1[i][0]=(dp1[i][0]+dp1[i-1][2]*(k-2))%mod;
        if(k>=3)dp1[i][0]=(dp1[i][0]+dp1[i-1][0]*(k-3))%mod;
        dp1[i][1]=(dp1[i-1][2]+dp1[i-1][0])%mod;
        dp1[i][2]=(dp1[i-1][1]+dp1[i-1][0])%mod;
    }
    dp2[0][1]=1;
    dp2[0][0]=0;
    for(int i=1;i<=200050;i++){
        dp2[i][0]=(dp2[i][0]+dp2[i-1][1]*(k-1))%mod;
        dp2[i][0]=(dp2[i][0]+dp2[i-1][0]*(k-2))%mod;
        dp2[i][1]=(dp2[i-1][0])%mod;
    }
    ll l=0,r=0;
    FOR(i,1,n){
        scanf("%d",&A[i]);
        if(i%2){
            if(A[i]!=-1)odd.push_back(i);
        }
        else{
            if(A[i]!=-1)even.push_back(i);
        }
    }
    if(odd.size()){
        l=(dp2[odd[0]/2][0]+dp2[odd[0]/2][1])%mod;
        //cout<<l<<endl;
        for(int i=0;i<odd.size()-1;i++){
            int diff=odd[i+1]-odd[i];
            diff=diff/2-1;
           // cout<<diff<<endl;
            if(A[odd[i]]==A[odd[i+1]]){
                l=(l*dp2[diff][0])%mod;
            }
            else{
                l=(l*(dp1[diff][0]+dp1[diff][1])%mod)%mod;
            }
        }
        int g=(n-odd[odd.size()-1])/2;
        if(g){
            l=(l*(dp2[g][0]+dp2[g][1])%mod)%mod;
        }
       // cout<<l<<endl;
    }
    else{
        l=k;
        for(int i=3;i<=n;i+=2)l=(l*(k-1))%mod;
    }
    if(even.size()){
        r=(dp2[even[0]/2-1][0]+dp2[even[0]/2-1][1])%mod;
        for(int i=0;i<even.size()-1;i++){
            int diff=even[i+1]-even[i];
            diff=diff/2-1;
            if(A[even[i]]==A[even[i+1]]){
                r=(r*dp2[diff][0])%mod;
            }
            else{
                r=(r*(dp1[diff][0]+dp1[diff][1])%mod)%mod;
            }
        }
        //cout<<r<<endl;
        int g=(n-even[even.size()-1])/2;
        if(g){
            r=(r*(dp2[g][0]+dp2[g][1])%mod)%mod;
        }
        //cout<<r<<endl;
    }
    else{
        r=k;
        for(int i=4;i<=n;i+=2)r=(r*(k-1))%mod;
    }
    cout<<(l*r)%mod<<endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值