Codeforces1068 D. Array Without Local Maximums(dp)

题意:

有一个长度为n的数组a,每个元素a(i)在1到200之间,
且对于每一个元素a(i),都至少有一个相邻元素>=a(i),
现在数组中缺失了若干个位置的数,问原数组有多少种可能,
统计方案数,答案对998244353取模。

数据范围:n<=1e5

解法:

因为元素的范围很小,容易想到令d(i,j)表示第i个位置填j的方案数。
但是这题还涉及到相邻元素的大小关系,那么添加一维k变成d(i,j,k),
d(i,j,k)表示第i个位置填j,与前一个数关系为k的方案数即可

需要维护一个前缀和进行O(1)转移,不能O(n)暴力计算和

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
const int mod=998244353;
int d[maxm][205][3];
int a[maxm];
int n;
/*
d[i][j][0/1/2]表示第i位填j,和前一位的关系为k的方案数
k=0:a[i-1]<a[i]
k=1:a[i-1]=a[i]
k=2:a[i-1]>a[i]
*/
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    //a[1],init
    for(int j=1;j<=200;j++){
        if(a[1]==-1||j==a[1]){//可以填j的情况
            d[1][j][0]=1;
        }
    }
    //
    for(int i=2;i<=n;i++){
        //
        int sum=0;//维护sum(d[i-1][1到(j-1)][k])
        for(int j=1;j<=200;j++){//0.<
            if(a[i]==-1||j==a[i]){
                d[i][j][0]=sum;
            }
            sum=(0LL+sum+d[i-1][j][0]+d[i-1][j][1]+d[i-1][j][2])%mod;
        }
        //
        for(int j=1;j<=200;j++){//1.=
            if(a[i]==-1||j==a[i]){
                d[i][j][1]=(0LL+d[i-1][j][0]+d[i-1][j][1]+d[i-1][j][2])%mod;
            }
        }
        //
        sum=0;//维护sum(d[i-1][(j+1)到200][k])
        for(int j=200;j>=1;j--){//2.>
            if(a[i]==-1||j==a[i]){
                d[i][j][2]=sum;
            }
            sum=(0LL+sum+d[i-1][j][1]+d[i-1][j][2])%mod;
        }
        //
    }
    int ans=0;
    for(int j=1;j<=200;j++){//a[n-1]<=a[n]
        ans=(0LL+ans+d[n][j][1]+d[n][j][2])%mod;
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/107526806