小Q有X首长度为A的不同的歌和Y首长度为B的不同的歌,现在小Q想用这些歌组成一个总长度正好为K的歌单,每首歌最多只能在歌单中出现一次, 在不考虑歌单内歌曲的先后顺序的情况下,请问有多少种组成歌单的方法

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/JMasker/article/details/86842035

小Q有X首长度为A的不同的歌和Y首长度为B的不同的歌,现在小Q想用这些歌组成一个总长度正好为K的歌单,每首歌最多只能在歌单中出现一次,在不考虑歌单内歌曲的先后顺序的情况下,请问有多少种组成歌单的方法。

下面介绍两种解法:
解法一(参考自牛客网ID为 我是牛我是牛牛 的代码(带有笔者自己写的解析)):

看作是01背包问题

#include<iostream>
using namespace std;
int B[201][1001]={0};   // B[i][j],歌单剩余长度为j,用来取1-i首歌的最多方案数
int w[201];   //w[i] :第i首歌占用的长度


int main(){
    int k,a,x,b,y,i,j;
   while(cin>>k){
        cin>>a>>x>>b>>y;
        for(i=0;i<=x+y;i++){
        	B[i][0]=1;  //B[i][0]都为1,意思是只要歌单长度为0,就算是1种方案。
		}
        
        for(i=1;i<=x;i++){
            w[i]=a;
        }
        for(i=x+1;i<=x+y;i++ ){
            w[i]=b;
        }
        for(i=1;i<=x+y;i++){
            for(j=1;j<=k;j++){
        /*  当当前所剩的长度>=歌曲i的长度时(忽略掉%1000000007)
				(当有i首歌 剩余长度为j 的方案总数)=不取这首歌的(即有i-1首歌 剩余长度为j的方案总数)+ 取这首歌(即有i-1首歌 剩余长度为j-这首歌长度p[i]的方案总数)
			否则(这首歌的长度已经超过歌单剩余长度了)
				(当有i首歌 剩余长度为j 的方案总数)=不取这首歌的(即有i-1首歌 剩余长度为j的方案总数) */
                if(j>=w[i])
                    B[i][j]=(B[i-1][j-w[i]]%1000000007+B[i-1][j]%1000000007)%1000000007;
                else
                    B[i][j]=B[i-1][j];
            }
        }
        cout<<B[x+y][k]<<endl; //B[x+y][k]就是当歌单长度为k,有x+y首歌时的最多方案数
    }
}

解法二:

用组合数,C[i][j]=C[i-1][j-1]+C[i-1][j] 表示i个里面取j个
先取i个a,(0<i<x),如果(k-ia)%b==0&&(k-ia)/b<=y,那么证明这种取法可以,这种取法共有c[x][i]×c[y][(k-ia)/b]种。

(组合数的计算参考自牛客网ID为 阿道 :
由C(n,k) = C(n-1,k) + C(n-1,k-1);
对应于杨辉三角:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1 )
由于数据大,除了题目中说明的%1000000007外,笔者用了long long int,不然有的数据会溢出。

#include<iostream>
using namespace std;



int main(){
   int k,a,x,b,y,i,j;
    long long int count=0;
    long long int c[101][101];
   while(cin>>k){
   		cin>>a>>x>>b>>y;
   		c[0][0]=1;
   		for(i=1;i<=100;i++){
   			c[i][0]=1;
   			for(j=1;j<=100;j++){
   				c[i][j]=(c[i-1][j-1]+c[i-1][j])%1000000007;
			   }
		}
   		
   		
   		for(i=0;i<=k/a&&i<=x;i++){
   			if((k-i*a)%b==0&&(k-i*a)/b<=y)
   				count=(count+(c[x][i]*c[y][(k-i*a)/b])%1000000007)%1000000007;
            
		}
   		cout<<count<<endl;
   		
   }
}

//以上两种方法皆通过牛客网测试
//本文章由笔者原创,记录和分享自己的学习历程,转载请注明出处

展开阅读全文

没有更多推荐了,返回首页