1. 程式人生 > >Codeforces Round #518 (Div. 2) D. Array Without Local Maximums dp

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

題目連結: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;
}