[arc068f]Solitaire

探讨了在特定条件下从1到n的整数通过双端队列进行删除操作的有效序列数量,通过贪心策略划分单调递减序列,并利用动态规划求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

将1-n顺序加入双端队列(每次可加头可加尾),再删除(每次可删头可删尾),求有多少种删除序列,使得1是第k个被删的。

做法

考虑什么样的删除序列存在对应的加入序列且合法。
1、第k个是1。
2、前k个元素能拆分成两个单调下降序列。
3、第k个后的元素每个位置都大于等于后缀最大值或小于等于后缀最小值。
4、前k个元素拆分出的单调下降序列其中一个的最小值大于等于第k个后的元素的最大值。
这些性质不难发现。
然后我们考虑一种贪心划分单调下降序列的方法,使得任意划分方法能扭转成这种划分,那就是能往第一个塞就往第一个塞,否则往第二个塞。
设f[i,j,t=1/2]表示把n~i这些元素分配给两个单调下降序列,其中有j个第二个单调下降序列的末尾元素没有加入到删除序列中,第i个元素属于第t个单调下降序列的方案数。
i-1如果放到第二个序列,则不能马上放入到删除序列中否则违背贪心划分,因此转移到f[i-1,j+1,2]。
i-1如果放到第一个序列,则原本不能放入到删除序列的第二个单调下降序列元素均可放入到删除序列,求后缀和即可。
最终方案是f[1,n-k,1],后面的显然可以2的次幂。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=2000+10,mo=1000000007;
int f[maxn][maxn][3],two[maxn];
int i,j,k,l,t,n,m,ans;
int main(){
    scanf("%d%d",&n,&k);
    two[0]=1;
    fo(i,1,n) two[i]=(ll)two[i-1]*2%mo;
    f[n+1][0][2]=1;
    fd(i,n+1,2){
        fd(j,n,0) (f[i][j][1]+=f[i][j+1][1])%=mo;
        fo(j,0,n)
            fo(t,1,2){
                (f[i-1][j+1][2]+=f[i][j][t])%=mo;
                (f[i-1][j][1]+=f[i][j][t])%=mo;
            }
    }
    ans=f[1][n-k][1];
    ans=(ll)ans*two[max(n-k-1,0)]%mo;
    (ans+=mo)%=mo;
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值