【DP】Codeforces - 1067A - Array Without Local Maximums
阿新 • • 發佈:2018-12-25
題目連結<https://cn.vjudge.net/problem/1983591/origin>
題意:
有一個長度為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兩種情況做不同的轉移。
注意:
- 中間步驟會爆int,最好直接開long long。
- 字首和因為做了一個取模操作,後面的不一定會比前面的大,所以字首和做減法的時候需要加上一個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); }