而後是我這個菜雞的我的理解(推薦上面那篇博客,講的比我好多了)c++
因爲從小到大插入,因此最終序列的兩邊必定要比中間要大,能夠看作一個\(V\)字型序列git
爲了取出\(1\),咱們必定會取完一整個單調的序列和另外一個單調的序列的一部分github
僞裝咱們已經取完了前\(K\)個數,那麼剩下的數是一個單調的序列,選法總數就是\(2^{n-k-1}\),注意當序列只剩一個元素時,隊首和隊尾是等價的優化
考慮前\(K\)個數的選法,能夠DPspa
考慮前\(K\)個數構成了兩個單調遞減的序列,對於肯定的\(K\)個數(順序也是肯定的),只要存在一種方案,使得它可以被合法地加入雙端隊列併合法地取出,那麼該序列合法。故咱們只需一種最有可能合法的方案便可,若該方案合法,說明整個序列都是合法的code
借用PuFanyi的博客中的紅色、藍色和綠色序列的概念,因爲藍色序列的最小值>綠色序列的最大值,因此咱們要儘量把較大的加入藍色序列。這樣最有可能合法隊列
令\(f[i,j]\)表示到第i位,最小的一位爲\(j\)的方案數,\(j\)即爲紅色序列末尾get
因此考慮隊首和隊尾,對於較大的一個,即剩下的數中的最大值,若是存在這個大於\(j\)的數,把他放到藍色序列中,不然放入紅色序列中博客
也能夠選擇較小的那一個,若其比\(j\)小,將其放入紅色序列中it
考慮何時存在大於\(j\)的最大值。大於j的數有\(n-j\)個,其中\(i-2\)個已經被選,故\(n-j-i+2>0\)即\(n-j+1>=i\),至於紅色序列,任何一個\(<j\)的數都知足要求,由於他必定是全部選的數中最小的,因此沒有不存在的狀況
而後前綴和優化就能夠AC了
#include<bits/stdc++.h> using namespace std; #define go(i,a,b) for(int i=a;i<=b;++i) #define com(i,a,b) for(int i=a;i>=b;--i) #define mem(a,b) memset(a,b,sizeof(a)) #define fo(i,a) for(int i=0;i<a;++i) #define il inline #define int long long const int inf=0x3f3f3f3f,N=2010,mod=1e9+7; int n,m,dp[N]; il void read(int &x){ x=0;char c=getchar(),f=1; while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); } while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); } x*=f; } signed main(){ read(n),read(m); dp[n]=1; go(i,1,m){ com(j,n,1){ if(n-j+1<i) dp[j]=0; else (dp[j]+=dp[j+1])%=mod; } } int ans=1; go(i,1,n-m-1) ans=ans*2%mod; printf("%lld",ans*dp[1]%mod); return 0; }
一份暴力代碼幫助本身理解
#include<bits/stdc++.h> using namespace std; #define go(i,a,b) for(int i=a;i<=b;++i) #define com(i,a,b) for(int i=a;i>=b;--i) #define mem(a,b) memset(a,b,sizeof(a)) #define fo(i,a) for(int i=0;i<a;++i) #define il inline #define int long long const int inf=0x3f3f3f3f,N=2010,mod=1e9+7; int n,m,dp[N][N]; il void read(int &x){ x=0;char c=getchar(),f=1; while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); } while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); } x*=f; } signed main(){ read(n),read(m); go(i,1,n) dp[1][i]=1; go(i,2,m){ go(j,1,n){ if(n-j-i+1>=0) dp[i][j]=dp[i-1][j]; //檢查當前是否存在合法且最大的數放入藍色序列 go(k,j+1,n){ if(n-k-i+1>=0) (dp[i][j]+=dp[i-1][k])%=mod; //檢查dp[i-1][k]是否合法且k是否爲藍色序列的結尾(即只有藍色序列的狀況) } } } int ans=1; go(i,1,n-m-1) ans=ans*2%mod; printf("%lld",ans*dp[m][1]%mod); return 0; }