码迷,mamicode.com
首页 > 其他好文 > 详细

AT2301 Solitaire

时间:2019-04-23 19:17:57      阅读:113      评论:0      收藏:0      [点我收藏+]

标签:生成   dig   ref   方案   amp   ring   arc   class   子序列   

传送门

这里提供智障的\(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

标签:生成   dig   ref   方案   amp   ring   arc   class   子序列   

原文地址:https://www.cnblogs.com/lcxer/p/10758089.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!