还在实习的我今天有同学问我了一道编程题说是2018年腾讯校招的笔试题(我只是个即将大四的菜逼-哈哈哈)
小Q的歌单:小Q有x首长度为A的不同歌和y首长度为B的歌,现在小Q想用这些歌组成一个总长度
正好为k的歌单,每首歌只能在歌单中出现一次,在不考虑歌单内歌曲的先后顺序的情况下问有多少种组合方式
输入描述:
每个输入包含一个测试用例
每个测试用例的第一行包含一个整数,表示歌单的总长度(当然得大于0咯)
接下来一行输入四个整数分别表示第一个歌的长度a和数量x,第二首歌的长度b和数量y,保证a!=b
输出描述:
输出一个整数,表示组成歌单的方法取模
#include<stdio.h>
long long c[105][105];
const int mod = 1000000007;//为什么要用100000007呢其实我也不是很清楚,这里可能只是需要一个很大很大的基数
void init()//建一个杨辉三角 至于为什么要建一个杨辉三角下面我会详细说明
{
int i,j;
c[0][0] = 1;
for(i=1;i<101;++i)
{
c[i][0]=1;
for(j=1;j<101;++j)
{
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
}
int main()
{
int k,a,b,x,y;
long long ans=0;
int i;
init();
scanf(“%d”,&k);
scanf(“%d%d%d%d”,&a,&x,&b,&y);2 3 3 3
for(i=0;i<x+1;++i)
{
if(i*a<k+1 && (k-i*a)%b == 0 && (k-a*i) / b < y+1)//判断组合
{
ans=(ans + (c[x][i]*c[y][(k-a*i)/b]) % mod) % mod;//为什么是*呢,因为是排列
break;//进入到if里其实就可以break了,这样避免往后的判断能降低时间复杂度,增加效率
}
}
printf(“%lld\n”,ans);
return 0;
}
下面讲一下杨辉三角的作用:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5
1 6 15 20 15
比如输入:
5 (总长度5)
3 4 5 6 4个长度为3的A 6个长度为5的B
6 (六种组合方式)
ans=(ans + (c[x][i]*c[y][(k-a*i)/b]) % mod) % mod;
当i=0时If条件就已经成立c[x][0]=1 (k-a*i)/b=1(几个b可以组成)
c[4][0]*c[6][1]=1*6=6
因为啥呢4个长度为3的a(杨辉三角第四行) 6个长度为5的b(杨辉三角第6行)
下面是我在linux下测试的结果:
如果还没理解自己再输入几个组合试试对比杨辉三角
方法相同自己理解吧!