一、原题目
题目描述:小Q有X首长度为A的不同的歌和Y首长度为B的不同的歌,现在小Q想用这些歌组成一个总长度正好为K的歌单,每首歌最多只能在歌单中出现一次,在不考虑歌单内歌曲的先后顺序的情况下,请问有多少种组成歌单的方法。
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含一个整数,表示歌单的总长度K(1<=K<=1000).
接下来的一行包含四个正整数,分别表示歌的第一种长度A(A<=10)和数量X(X<=100)以及歌的第二种长度B(B<=10)和数 量Y(Y<=100).保证A不等于B。
输出描述:
输出一个整数,表示组成歌单的方法取模。因为答案可能会很大,输出对1000000007取模的结果。
输入示例:
5
2 3 3 3
输出示例:
9
二、题目分析
这道题目可以转换为一个排列组合的问题。长度为A和长度为B可以看成红球和白球,记红球两分,白球三分(分数对应歌曲长度),红白球的数量表示歌的首数。现在的问题就是一个得到一个具体的分数,如9分,有 多少种拿球方式。
另外就得考虑如果分配红白球数量的问题了。这样就会想如果拿了0个红球,白球有多少种拿法,如果拿了1个、2个、3个红球,白球各有多少种拿法。然后把红球拿法的种数乘以白球拿的种数就等于最后一个具体的分数的所有取法。
当然具体的分配过程需要一个公式来表示:首先表示拿到了i1个红球,那么i1*A<=k(代码中我被我设置为了length),同时还要满足(k-i1*A)/B==0这保证了拿了i1个红球之后,剩下的可以用白球。如果不等于0那么说明红球拿法不对。最后还需要保证的是(K--i1*A)/B<=Y不能操作白球数量。
代码:代码质量不是很好,我子集参考着写的。
package 面试题目;
import java.util.Scanner;
public class qMusic {
public static void main(String[] args) {
//这一部分是设置k(length),A,X,B,Y的值
Scanner scan = new Scanner(System.in);
System.out.print("请输入四个数字:");
int length = scan.nextInt(); //设置总长度
int A = scan.nextInt(); //设置长度为A的歌
int X = scan.nextInt(); //设置长度为A的歌X首
int B = scan.nextInt(); //设置长度为B的歌
int Y = scan.nextInt(); //设置长度为B的歌Y首
System.out.println("总长度:"+length+",长度为A的歌的长度"+A+",长度为A的歌有:"+X+"长度为A的歌的长度"+"长度为A的歌有:"+Y);
scan.close();
//这里是关于一个排列组合的问题,C[N][M]的意思表示的是从N个歌曲里面选M首的选法
int c[][] = new int[105][105];
c[0][0] = 1;
for(int i=1;i<100;i++){
c[i][0] = 1;
for(int y=1;y<100;y++){
c[i][y]=(c[i-1][y-1]+c[i-1][y]) % 1000000007;
}
}
//最后是计算出结果
int sum = 0;
for(int i1=0;i1<X;i1++){
if(i1*A<=length&&(length-A*i1)%B==0&&(length-A*i1)/B<=Y){
sum=(sum+(c[X][i1]*c[Y][(length-A*i1)/B]));
}
}
System.out.println(sum %1000000007 );
}
}
运行结果:
参考:
1.优快云博客:https://blog.youkuaiyun.com/yue_jijun/article/details/81105030#commentBox
2.牛客网:https://www.nowcoder.com/questionTerminal/f3ab6fe72af34b71a2fd1d83304cbbb3
介于自身能力有限,希望大家看后多多指点!