AT2301 Solitaire

Posted lcxer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AT2301 Solitaire相关的知识,希望对你有一定的参考价值。

传送门

这里提供智障的\(O(n^2)\)做法
其实是有\(O(logn)\)做法的,但是我太菜了想不出来

Solution:

首先可以发现生成的序列一定是一个两边向中间单调递减的序列
这样就可以发现我们的删除序列也是一个有两个单调递减的子序列的序列
然后我们就可以设\(f[i][j]\)为当前确定了\(i\)个数,最小值为\(j\)的方案数
然后我们发现这两个序列中有一个序列的最后一个元素就是\(1\),设这个序列为\(A\),则另一个序列为\(B\)
然后有一个性质:对于\(f[i][j]\),这个数如果加进\(A\),那么它就要小于\(j\)(因为\(A\)最后一个数得是\(1\),最小的数一定在\(A\)里),如果加进\(B\)序列,那么它一定要是剩下的数中最大的(思考一下就知道了,实在不行就模拟一下)
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
void read(int &x) {
    char ch; bool ok;
    for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define rg register
const int maxn=2010,mod=1e9+7;
int n,k,ans,f[maxn][maxn],sum[maxn];
int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int del(int x,int y){return x-y<0?x-y+mod:x-y;}
int mi(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=mul(ans,a);
        b>>=1,a=mul(a,a);
    }
    return ans;
}
int main(){
    read(n),read(k);f[0][n+1]=1;
    for(rg int i=1;i<=k;i++){
        sum[n+1]=f[i-1][n+1];
        for(rg int j=n;j;j--)sum[j]=add(sum[j+1],f[i-1][j]);
        for(rg int j=1;j<=n-i+1;j++)f[i][j]=add(f[i][j],sum[j]);
    }
    printf("%d\n",mul((del(f[k][1],f[k-1][1])),mi(2,n-k-1)));
}

以上是关于AT2301 Solitaire的主要内容,如果未能解决你的问题,请参考以下文章

read ECONNRESET at TLSWrap.onStreamRead (internal/stream_base_commons.js:209:20) { errno: -4077(代码片段

ARC 68F - Solitaire(dp)

如何在 Javadoc 中使用 @ 和 符号格式化代码片段?

ARC 68F - Solitaire(dp)

Solitaire 纸牌游戏 - 如何编程恢复游戏功能?

UVa 10651 Pebble Solitaire(DP 记忆化搜索)