Codeforces Round #518 (Div. 2) D. Array Without Local Maximums dp

版权声明:本博客内容基本为原创,如有问题欢迎联系,转载请注明出处 https://blog.csdn.net/qq_41955236/article/details/83477840

题目链接:http://codeforces.com/contest/1068/problem/D

题意:

       给你n个数,其中有一些数字被遗忘了(被遗忘的数输入位-1),但是知道所有的数满足:a1≤a2,an≤an−1 同时对所有的2~n-1种的数满足 ai≤max(ai−1,ai+1),问给你的数有多少种正确的填法。

做法:

      感觉上好像是要用dp的,但是参考了大佬的博客,菜知道了这道题dp的含义。大概就是三维,dp[2][203][3]代表的是到达第i个数时,在确实这个数为j的情况下,它左边的那个数小于/等于/大于它时候的方法数。

      转移方程让我想了很久吧,尤其是第三维的操作,当等于的时候,只要把左边那个数方法发012都加上即可(因为是左边那个数在确定为j的情况下的方法数,而这个数当前要等于它,所以直接加),而小于的时候,因为是从1for到200的,所以只要存一个前缀和,在处理之前把数进行赋值,再相加即可(即如果这个数确定为5,那么sum当前还未加前保存的是左边的数为1234所有方法的总和),再另外,如果是大于的话同理,但是要从200for到1,另外还要注意,如果是大于的话不要加上所有的,起码左边那个数的小于不能加,因为这样会不符合题意(这里是为什么,我现在脑子还有点糊。。)。大概就是这样吧。。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int maxn=100005;
ll dp[2][205][3];
//0为小于 1为等于 2为大于
ll n,a[maxn];
int main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    int p=0;
    for(int i=1;i<=200;i++){
        if(a[1]==-1||a[1]==i)
            dp[p][i][0]=1;
    }
    for(int i=2;i<=n;i++){
        for(int j=1;j<=200;j++){
            if(a[i]==-1||a[i]==j)
                dp[p^1][j][1]=(dp[p][j][0]+dp[p][j][1]+dp[p][j][2])%mod;
            else dp[p^1][j][1]=0;
        }
        ll sum=0;
        for(int j=1;j<=200;j++){
            if(a[i]==-1||a[i]==j)
                dp[p^1][j][0]=sum;
            else dp[p^1][j][0]=0;
            sum=(sum+dp[p][j][0]+dp[p][j][1]+dp[p][j][2])%mod;
        }
        sum=0;
        for(int j=200;j>=1;j--){
            if(a[i]==-1||a[i]==j)
                dp[p^1][j][2]=sum;
            else dp[p^1][j][2]=0;
            sum=(sum+dp[p][j][1]+dp[p][j][2])%mod;
        }
        p^=1;
    }
    ll ans=0;
    for(int i=1;i<=200;i++){
        ans=(ans+dp[p][i][1]+dp[p][i][2])%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41955236/article/details/83477840