牛客提高D6t2 破碎的序列

分析

我们不难发现对于偶数的情况只要相邻两个数不相等即可

而对于奇数的情况只要中间恰好隔一个数的两个数不相等即可

于是我们又dp[i][0/1]表示考虑到第i位,这一位和它后面离它最近的一个确定的数是否相等

每次从i-1转移即可

注意对于奇数的情况最终答案要n-1和n的dp值相乘以保证合法

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int mod = 998244353;
int dp[200100][2],a[200100],b[200100],n,m,k; 
int main(){
    int i,j;
    scanf("%d%d%d",&n,&k,&m);
    for(i=1;i<=n;i++)scanf("%d",&a[i]);
    if(m==0){
      for(i=n-1;i>0;i--)b[i]=a[i+1]?a[i+1]:b[i+1];
      if(a[1]&&a[1]==b[1]){
        dp[1][0]=0;
        dp[1][1]=1;
      }else if(a[1]){
        dp[1][1]=0;
        dp[1][0]=1;
      }else {
        dp[1][1]=1;
        dp[1][0]=k-1;
      }
      for(i=2;i<=n;i++)
        if(a[i]&&a[i]==b[i]){
          dp[i][0]=0;
          dp[i][1]=dp[i-1][0];
        }else if(a[i]){
          dp[i][1]=0;
          dp[i][0]=dp[i-1][0];
        }else {
          dp[i][1]=dp[i-1][0];
          dp[i][0]=((dp[i][0]+1ll*dp[i-1][0]*(k-2)%mod)%mod+1ll*dp[i-1][1]*(k-1)%mod)%mod;
        }
      printf("%d\n",(dp[n][0]+dp[n][1])%mod);
    }else {
      for(i=n-2;i>0;i--)b[i]=a[i+2]?a[i+2]:b[i+2];
      for(i=1;i<=2;i++){
        if(a[i]&&a[i]==b[i]){
          dp[i][0]=0;
          dp[i][1]=1;
        }else if(a[i]){
          dp[i][1]=0;
          dp[i][0]=1;
        }else {
          dp[i][1]=1;
          dp[i][0]=k-1;
        }
      }
      for(i=3;i<=n;i++)
        if(a[i]&&a[i]==b[i]){
          dp[i][0]=0;
          dp[i][1]=dp[i-2][0];
        }else if(a[i]){
          dp[i][1]=0;
          dp[i][0]=dp[i-2][0];
        }else {
          dp[i][1]=dp[i-2][0];
          dp[i][0]=((dp[i][0]+1ll*dp[i-2][0]*(k-2)%mod)%mod+1ll*dp[i-2][1]*(k-1)%mod)%mod;
        }
      printf("%d\n",1ll*((dp[n][0]+dp[n][1])%mod)*((dp[n-1][0]+dp[n-1][1])%mod)%mod);
    }
    return 0;
}
posted @ 2019-08-26 16:37  水题收割者  阅读(161)  评论(0编辑  收藏  举报