而后是我这个菜鸡的我的理解(推荐上面那篇博客,讲的比我好多了)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; }