1. 程式人生 > >【DP】Codeforces

【DP】Codeforces

題意:

有一個長度為N的序列(2≤n≤1e5)滿足關係:

a1≤a2,an≤an−1,ai≤max(ai−1,ai+1)。

每一個ai的範圍是[1,200],有一些ai是確定的,有一些是不確定的,問有多少種情況。答案對998244353取模。

題解:

從頭到尾掃一遍,列舉每一位放數字的情況。

開一個數組dp[i][j](1≤i≤200,j={0,1,2})表示當前位置放數字i,與前一位的大小情況:

  • dp[i][0]表示當前位放i且比前一位數字小
  • dp[i][1]表示當前位放i且和前一位數字一樣
  • dp[i][2]表示當前位放i且比前一位數字大

另外開一個數組sum[i][j](1≤i≤200,j={0,1,2})是上一位dp陣列的字首和。

然後兩者之間互相轉移,對於是-1和不是-1兩種情況做不同的轉移。

注意:

  1. 中間步驟會爆int,最好直接開long long。
  2. 字首和因為做了一個取模操作,後面的不一定會比前面的大,所以字首和做減法的時候需要加上一個mod。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+7;
const ll mod=998244353;
ll a[N];
ll dp[300][3],sum[300][3];
int main(){
    ll n;
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    if(a[1]==-1){
        for(ll i=1;i<=200;i++){
            dp[i][1]=1;
            sum[i][1]=(sum[i-1][1]+1)%mod;
        }
    }
    else{
        dp[a[1]][1]=1;
        for(ll i=a[1];i<=200;i++)
            sum[i][1]=1;
    }
    for(ll i=2;i<=n;i++){
        if(a[i]==-1){
            for(ll j=1;j<=200;j++){
                dp[j][1]=(dp[j][0]+dp[j][1]+dp[j][2])%mod;
                dp[j][0]=(sum[200][0]-sum[j][0]+sum[200][1]-sum[j][1]+mod)%mod;
                dp[j][2]=(sum[j-1][0]+sum[j-1][1]+sum[j-1][2])%mod;
                if(i==2) dp[j][0]=0;
            }
        }
        else{
            for(ll j=1;j<a[i];j++) dp[j][0]=dp[j][1]=dp[j][2]=0;
            for(ll j=a[i]+1;j<=200;j++) dp[j][0]=dp[j][1]=dp[j][2]=0;
            dp[a[i]][1]=(dp[a[i]][0]+dp[a[i]][1]+dp[a[i]][2])%mod;
            dp[a[i]][0]=(sum[200][0]-sum[a[i]][0]+sum[200][1]-sum[a[i]][1]+mod)%mod;
            dp[a[i]][2]=(sum[a[i]-1][0]+sum[a[i]-1][1]+sum[a[i]-1][2])%mod;
            if(i==2) dp[a[i]][0]=0;
        }
        for(ll j=1;j<=200;j++){
            sum[j][0]=(sum[j-1][0]+dp[j][0])%mod;
            sum[j][1]=(sum[j-1][1]+dp[j][1])%mod;
            sum[j][2]=(sum[j-1][2]+dp[j][2])%mod;
        }
    }
    if(a[n]==-1)
        printf("%lld\n",(sum[200][0]+sum[200][1])%mod);
    else
        printf("%lld\n",(dp[a[n]][0]+dp[a[n]][1])%mod);
}