• bzoj 5215: [Lydsy2017省队十连测]商店购物


    5215: [Lydsy2017省队十连测]商店购物

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 129  Solved: 50
    [Submit][Status][Discuss]

    Description

    在 Byteland一共开着 n家商店,编号依次为 1到 n,其中编号为1到 m的商店有日消费量上限,第 i家商店的日消
    费量上限为wi。Byteasar每次购物的过程是这样的:依次经过每家商店,然后购买非负整数价格的商品,并在结账
    的时候在账本上写上在这家商店消费了多少钱。当然,他在这家商店也可以什么都不买,然后在账本上写上一个0
    。这一天, Byteasar日常完成了一次购物,但是他不慎遗失了他的账本。他只记得自己这一天一共消费了多少钱
    ,请写一个程序,帮助 Byteasar计算有多少种可能的账单。 
     

    Input

    第一行包含三个正整数 
    n, m, k,分别表示商店的个数、有限制的商店个数以及总消费量。
    第二行包含 m个整数,依次表示 w1;w2...wm。 
    1 ≤ m ≤ n,0≤ wi ≤ 300,1 ≤ n, k ≤ 5000000
    m<=300
     

    Output

    输出一行一个整数,即可能的账单数,由于答案可能很大,请对1000000007取模输出。 
     

    Sample Input

    3 2 8
    2 1

    Sample Output

    6
    HINT
    6 种方案分别为:{0; 0; 8}; {1; 0; 7}; {2; 0; 6}; {0; 1; 7};
    {1; 1; 6}; {2; 1; 5}。

    HINT

     

    Source

     
    前面背包,后面组合算。
     
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int ha=1000000007;
    const int maxn=10000000;
    int jc[maxn+5],ni[maxn+5];
    int f[2][100005],n,m,K,tot;
    int ans=0,a[305],now,pre;
    
    inline int add(int x,int y){
    	x+=y;
    	return x>=ha?x-ha:x;
    }
    
    inline int ksm(int x,int y){
    	int an=1;
    	for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
    	return an;
    }
    
    inline void init(){
    	jc[0]=1;
    	for(int i=1;i<=maxn;i++) jc[i]=jc[i-1]*(ll)i%ha;
    	ni[maxn]=ksm(jc[maxn],ha-2);
    	for(int i=maxn;i;i--) ni[i-1]=ni[i]*(ll)i%ha;
    }
    
    inline int C(int x,int y){
    	if(x<y) return 0;
    	return jc[x]*(ll)ni[y]%ha*(ll)ni[x-y]%ha;
    }
    
    inline void dp(){
    	f[0][0]=1;
    	for(int i=1;i<=m;i++){
    		tot+=a[i];
    		pre=now,now^=1;
    		for(int j=0,sum=0;j<=tot;j++){
    			sum=add(sum,f[pre][j]);
    			if(j>a[i]) sum=add(sum,ha-f[pre][j-a[i]-1]);
    			f[now][j]=sum;
    		}
    	}
    }
    
    inline void calc(){
    	if(!n){
    		if(K<=tot) ans=f[now][K];
    		else ans=0;
    	}
    	else for(int i=min(K,tot);i>=0;i--) ans=add(ans,f[now][i]*(ll)C(K-i+n-1,K-i)%ha);
    }
    
    int main(){
    	init();
    	scanf("%d%d%d",&n,&m,&K);
    	for(int i=1;i<=m;i++) scanf("%d",a+i);
    	n-=m;
    	dp();
    	calc();
    	printf("%d
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    乘坐飞机时,有什么事情是机长和机上工作人员不想让乘客知道的?
    北京有哪些被废弃的地方值得一看?推荐理由是什么?
    在读硕士或博士是如何养活自己的?
    怎样有效提高记忆力?
    北京值得去的、不为人知的景点(或展览馆、美术馆、公园)有哪些?
    你收藏了哪些藏品?
    如何抓到入侵网站的黑客?
    中国姓氏的区域性?
    python之入门,你好,中国
    Eclipse 内置浏览器
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8762128.html
Copyright © 2020-2023  润新知