【AtCoder Regular Contest 068 F】Solitaire

动态规划。

题目大意:

给你一个双端队列,你要依次将 $1\sim n$ 插入队列。然后将它们都弹出来。问有多少种不同的删除序列,满足第 $k$ 个删除的数是 $1$。

题解:

这个删除序列显然由不超过两个下降子序列组合而成。

我们考虑末尾有连续 $m$ 个数被取了,当前最小的数是 $x$ 且不与 $m$ 个连续。

那么,$x$ 所在的一端后面可以任意取,而另外一端只能取 $n-m$,否则将不满足从小到大插入的条件。

我们按位确定每一位的值。

令 $f_{i,j}$ 表示前 $i$ 个位置确定了,当前的最小的数为 $j$。

如果放在最小的数后面,那么可以转移到 $f_{i+1,t}$($t\lt j$)。

如果放在另外一端后面,那么可以转移到 $f_{i+1,j}$。

可以用前缀和优化。

取完 $1$ 之后的可以任意删,所以要乘 $2^{n-k-1}$。

时间复杂度 $O(nk)$。

Code:

int f[2003],n,k,ans;
const int md=1e9+7;
int main(){
    __builtin_scanf("%d%d",&n,&k);
    f[n+1]=1;
    for(int i=1;i<k;++i)for(int j=n-i+1;j>1;--j)(f[j]+=f[j+1])%=md;
    for(int i=2;i<=n-k+2;++i)ans=(ans+f[i])%md;
    for(int i=n-k-1;i>0;--i)ans=ans*2%md;
    __builtin_printf("%d",ans);
    return 0;
}