• 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
    ",mul((del(f[k][1],f[k-1][1])),mi(2,n-k-1)));
    }
    
  • 相关阅读:
    《程序员修炼之道:从小工到专家》阅读笔记(一)
    第十一周进度报告
    用户模板和用户场景
    第十周进度报告
    团队冲刺第十天
    团队冲刺第九天
    团队冲刺第八天
    第一阶段用户评价
    第十二周总结
    第十一周总结
  • 原文地址:https://www.cnblogs.com/lcxer/p/10758089.html
Copyright © 2020-2023  润新知