zoukankan      html  css  js  c++  java
  • NOIP模拟 篮球比赛2

    题目描述

    由于Czhou举行了众多NOIP模拟赛,也导致放学后篮球比赛次数急剧增加。神牛们身体素质突飞猛进,并且球技不断精进。这引起了体育老师彩哥的注意,为了给校篮球队找到势均力敌的对手,彩哥找到了Czhou神,想要和机房篮球队进行多场友谊赛。Czhou为了顾全校篮球队面子,决定派出配合默契又不至于吊打校篮球队的阵容。
    而机房神牛的能力值受到游戏时长,训练时长,个人基础值得影响,可能会不断变化。所以Czhou想根据神牛当天状态从中选出若干名选手,使他们的能力值和等于k。
    Input:

    一行三个数n,k,l。表示机房有n个神牛,选出队员能力值和为k,每个神牛的能力最大值<=L且>=0。
    

    Ouput:

    输出一个数,表示方案数,方案满足选出若干选手使能力和为k。因为答案比较大,最后模10^9+7。
    

    Sample.in

    2 2 2
    

    Sample.out

    6
    

    样例说明:神牛的能力值可能为(0,2)(1,2)(1,1)(2,0)(2,1)(2,2),这样都可以选出一些数字使他们的能力值和为2。
    对于(0,2)表示第一只牛能力值为0,第二只牛能力为2
    类似的
    对于(1,2)选出2即满足要求。
    对于(1,1)选出全部选手即满足要求。
    所以(0,2)(1,1)都是满足要求的方案。
    数据范围:
    n,k<=20
    0<=L<=10^9.

    解法

    1.爆搜+背包

    这个当然是过不了的。

    2.状压DP(from hzwer)

    排列组合以及其余的dp算法似乎都会涉及重复统计的问题
    dp[i][state] 表示前i位,state的二进制每一位表示和为(1~k),1表示可以取到,0表示取不到,0<=state<(1<<K)-1
    枚举第i+1个取的数 f[i][j]->f[i+1][(i|(i<<x)|(1<<(x-1)))&((1<<K)-1)]
    这是一个2n*n2的dp,但是状压废状态比较多,剪掉废状态即可AC。。。

    3.记搜

    很明显,这道题是可以记搜的,代码注释很详细,也没什么要讲的。

    #include<bits/stdc++.h>
    const int mod=1e9+7;
    const int N=1<<21;
    typedef long long ll;
    using namespace std;
    int n,k,l,last,maxx;
    int Pow[27],f[24][1300007];
    /*
    	Pow记(l+1)的i次幂,,f是记搜.
    	f[i][j]的j是二进制表示的状态.0为取,1不取.
    	f[i][j]记当计算到第i个人状态为j时能够取到的值的的方案数。
    */
    int dfs(int cnt,int now){//cnt表示第几个人,now表示当前能得到的值的状态
        if(f[cnt][now]!=-1) return f[cnt][now];
        if(now&last) return f[cnt][now]=Pow[n-cnt+1];
        /*
    		如果此时已经可以取到k,则后面的人无论取多少都可以
          	后面的人取0~l的方案数为(l+1)的后面的人数(n-cnt+1)次方
         */
        if(cnt==n+1) return f[cnt][now]=(now&last);
        int res=0;
        long long temp;
        for(int i=0;i<=min(k,l);i++){
            temp=((ll)dfs(cnt+1,(now|(now<<i))&maxx))%mod;
            /*
            	&maxx防止超出n的范围
    		*/
            res=(res+temp)%mod;
        }
        if(l>k){
            temp=(((ll)((ll)dfs(cnt+1,now)%mod*(ll)(l-k))%mod))%mod;
            /*
    			如果当前的人取值大于k就一定不会做出贡献,对后面的状态的影响是等价的
                所以假设当前人取值大于k,跑一次.
            	所以直接计算一次再乘以(l-k)
    		*/
            res=(res+temp)%mod;
        }
        return f[cnt][now]=res%mod;
    }
    int main(){
    //	freopen("football.in","r",stdin);
    //	freopen("football.out","w",stdout);
        scanf("%d%d%d",&n,&k,&l);
        memset(f,-1,sizeof(f));
        Pow[0]=1;
        for(int i=1;i<=n;i++) Pow[i]=(ll)((ll)Pow[i-1]*(ll)(l+1))%mod;
        last=(1<<k);
        maxx=(1<<(k+1))-1;
        printf("%d
    ",dfs(1,1)%mod);
        return 0;
    }
    
  • 相关阅读:
    prototype.js超强的javascript类库
    MySQL Server Architecture
    Know more about RBA redo block address
    MySQL无处不在
    利用Oracle Enterprise Manager Cloud Control 12c创建DataGuard Standby
    LAMP Stack
    9i中DG remote archive可能导致Primary Database挂起
    Oracle数据库升级与补丁
    Oracle为何会发生归档日志archivelog大小远小于联机重做日志online redo log size的情况?
    Oracle Ksplice如何工作?How does Ksplice work?
  • 原文地址:https://www.cnblogs.com/Fast-Bird/p/11929350.html
Copyright © 2011-2022 走看看