[50]小Q的歌单-腾讯2018秋

2018-11-08  本文已影响28人  jdzhangxin

1.题目描述

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

2.题目解析

将两种长度的歌的数量进行遍历,如果满足总长度为K,计算该数量的组合C_n^m下共有多少种不同歌曲的组合方式。所以本题的关键是实现组合函数。

C_n^m = \frac{n!}{m!(n-m)!}\qquad

一般来说,时间复杂度是阶乘级O(n!)的函数是不可用的。这里需要用到杨辉三角。

杨辉三角

从上图可见,杨辉三角保存着所有组合数。所以,只要把部分杨辉三角保存起来,求解组合直接查表。对应的C[m][n]就是C_n^m

数学上规定0!=1

3.参考答案

#include <bits/stdc++.h>
using namespace std;
long long c[101][101]; // 保存杨辉三角
const int mod = 1000000007;

void init(int size) {
  c[0][0] = 1;
  for (int i = 1; i != size; i++) {
    c[i][0] = 1;
    for (int j = 1; j != size; j++){
      // 杨辉三角规则:当前值是上一行的两个肩上的值之和
      c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
    }
  }
}
int main() {
    // 构建杨辉三角
    init(101);
    // 获取输入参数
    int k = 0;// 歌单总长度
    scanf("%d",&k);
    int a = 0; // 第一种歌曲长度
    int x = 0; // 第一种歌曲数量
    int b = 0; // 第二种歌曲长度
    int y = 0; // 第二种歌曲数量
    scanf("%d%d%d%d",&a,&x,&b,&y);
    
    int res=0;
    // 遍历第一种歌曲数量可选用的数目0~x
    for (int i = 0; i <= x; i++) {
        int sum_a = i*a; // 第一种歌曲长度和
        int sum_b = k-i*a; // 第二种歌曲长度和
        if (sum_a <= k // 选取的第一种歌曲长度和不超过歌单总长度
            && sum_b%b == 0 // 除去第一种歌曲长度和,剩余长度必须是第二种歌曲长度的整数倍
            && sum_b/b <= y // 第二种歌曲数目不能超过歌曲总数
           ){
           // 组成歌单数目
           int count = (c[x][i] * c[y][sum_b/b]) % mod;
           res = (res + count) % mod; // 因为可能不止一种方式,多种方式数目累加。
        }
    }
    printf("%d\n", res);
  return 0;
}

牛客题目

上一篇下一篇

猜你喜欢

热点阅读