Codeforces Round #518 (Div. 2) D. Array Without Local Maximums dp
阿新 • • 發佈:2018-12-11
題目連結: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; }