【arc068F】Solitaire
阿新 • • 發佈:2018-05-28
iostream arc algorithm -i str 下一個 pac 滿足 ()
設f[i][j]表示,前k-1個數中,已確定了i個數,在確定的i個數中,最小值為j。
假定第一個單調序列是彈出1個一遍,那麽第二個單調序列就要滿足第3個性質。
每次新加一個數,如果加進第一個單調序列,顯然加入的數就要小於j
於是f[i][j]->f[i+1][k] (j>k)
如果如果加進第二個單調序列,顯然加入的數就要是當前沒加的數中最大的,只有這樣才能滿足第3條性質。
於是f[i][j]->f[i+1][j]。
註意一下邊界。
題目大意
有一個隊列,頭尾都可以進出。
首先將n個數1~n從小到大扔進隊列,然後將一次彈出隊列,求最後彈出來的排列中,第k個數為1的排列有多少種。
解題思路
我們來考慮一下一個合法排列的性質,
第k個數是1
前k-1個數是可以拆成一個或兩個單調遞減的序列。
前k-1個數中其中一個序列的最小值一定大於後n-k個數中的最大值。
考慮如何來滿足這個構造出這個排列。
先考慮後n-k-1個數,發現,這些數一定是有一個單調的隊列,每次彈出頭或尾來構成的,只要我們確定前k-1個數,就可以得出這個單調的隊列能構成的後n-k-1個數的方案,就是\(2^{n-k-1}\)。
然後,如何確定前k-1個數,且保證第2條性質呢?
假定第一個單調序列是彈出1個一遍,那麽第二個單調序列就要滿足第3個性質。
每次新加一個數,如果加進第一個單調序列,顯然加入的數就要小於j
於是f[i][j]->f[i+1][k] (j>k)
如果如果加進第二個單調序列,顯然加入的數就要是當前沒加的數中最大的,只有這樣才能滿足第3條性質。
於是f[i][j]->f[i+1][j]。
註意一下邊界。
#include <cmath> #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> #include <map> #include <bitset> #include <set> const int maxlongint=2147483647; const long long mo=1e9+7; const int N=3005; using namespace std; int n,k; long long ans,mi[N],f[N][N]; int main() { scanf("%d%d",&n,&k); mi[0]=1; for(int i=1;i<=n;i++) mi[i]=mi[i-1]*2%mo; for(int i=n;i>=2;i--) f[1][i]=1; for(int i=1;i<k-1;i++) { long long sum=f[i][n-i+1]; for(int j=n-i;j>=2;j--) { sum=(sum+f[i][j])%mo; f[i+1][j]=(f[i+1][j]+sum)%mo; } } for(int j=2;j<=n-k+2;j++) ans=(ans+f[k-1][j])%mo; if(k==1) ans=1; if(n-1-k<0) printf("%lld",ans); else printf("%lld",ans*mi[n-1-k]%mo); }
【arc068F】Solitaire