1. 程式人生 > >codeforces 1068d Array Without Local Maximums dp

codeforces 1068d Array Without Local Maximums dp

滿足 codeforce 數組 .com std || long getc pro

題目傳送門

  題目大意:給出一個長度為n的數組,這個數組有的數是給出的,有的數是固定的,且範圍都在[1,200]之間,要求這個數組中,每一個數字都小於等於 前後兩個數字的最大值,求方案數mod p。

  思路:一眼看出是個dp,但是不太擅長這個,看了大佬的題解,又加上了一些自己的思考。

  由於這個數組每一個元素都是前後相關的,所以應該是個線性dp的東西,既然是線性的,我們就先考慮每一個元素和前面一個元素的關系(沒法往後看,因為後面的元素都沒有得到),將當前這個數字和前面的數字進行比較,會得到“>”“=”“<”這樣三種狀態,如果我們用dp[ i ][ x ][ flag ]表示第i個位子填x,和前面元素關系是flag,flag有0,1,2三種狀態,分別表示大於,等於,小於。我們可以得到

  dp[i+1][ y ][0]=dp[i][ x ][0,1,2] (x<y)

  dp[i+1][ y ][1]=dp[i][ y ][0,1,2] (x==y)

  dp[i+1][ y ][2]=dp[i][ x ][1,2] (x>y)

  而對於第一個位置來說,顯然不會小於等於前一個,否則第二個格子就可以隨便填了,所以第一個格子只有狀態為0,值才等於1.

  得到了這個遞推式就可以dp了,需要註意的是,對於第一條遞推式,由於我要累加所有滿足(x<y)的x,很多人可能會枚舉x,但事實上我們只需要註意一下x的遍歷順序,把每次的值都累計在一個sum裏面就可以了。

  但是這道題我們更應該思考的是,為什麽要這樣dp?

  我的理解是,由於每個元素的限制條件其實是當前元素和前後元素的大小關系,也就是說合法性和大小關系有關,所以就對大小關系進行拆解(其實我覺得拆成<=和>就夠了)。而我保證了當前格子的情況都是合法的情況,不斷遞推,遞推到最後一個格子時,最後一個格子的絕對合法情況就是答案,即dp[n][x][1]+dp[n][x][2];

技術分享圖片
//#pragma comment(linker,"/STACK:102400000,102400000")
#include<cstdio>
#include<algorithm>
#include<iostream>
#include
<vector> #include<map> #include<set> #include<cstring> #include<cmath> #include<queue> #include<stack> #include<stdlib.h> //#include<unordered_map> #define lson l,mid,rt<<1 #define rson mid+1,r,(rt<<1)|1 #define CLR(a,b) memset(a,b,sizeof(a)) #define mkp(a,b) make_pair(a,b) typedef long long ll; using namespace std; inline int read(){ int x=0,f=1; char ch=getchar();while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();} while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();} return x*f;} const int maxn=1e5+10; ll p=998244353; ll dp[maxn][210][3]; int a[maxn],n; int main(){ cin>>n; for(int i=1;i<=n;i++) { a[i]=read(); } for(int x=1;x<=200;x++) { if(a[1]!=-1&&a[1]!=x)dp[1][x][0]=dp[1][x][1]=dp[1][x][2]=0; else dp[1][x][0]=1,dp[1][x][1]=dp[1][x][2]=0; } ll sum; for(int i=2;i<=n;i++) { sum=0; for(int x=1;x<=200;x++) { if(a[i]!=-1&&a[i]!=x)dp[i][x][0]=0; else dp[i][x][0]=sum; sum=(sum+dp[i-1][x][0]+dp[i-1][x][1]+dp[i-1][x][2])%p; } for(int x=1;x<=200;x++) { if(a[i]!=-1&&a[i]!=x)dp[i][x][1]=0; else dp[i][x][1]=(dp[i-1][x][0]+dp[i-1][x][1]+dp[i-1][x][2])%p; } sum=0; for(int x=200;x>0;x--) { if(a[i]!=-1&&a[i]!=x)dp[i][x][2]=0; else dp[i][x][2]=sum; sum=(sum+dp[i-1][x][1]+dp[i-1][x][2])%p; } } sum=0; for(int i=1;i<=200;i++){ sum=(sum+dp[n][i][1]+dp[n][i][2])%p; } printf("%lld\n",sum); }
View Code

codeforces 1068d Array Without Local Maximums dp