链接:https://ac.nowcoder.com/acm/problem/16429
来源:牛客网
题目描述
组合数表示的是从 n 个物品中选出 m 个物品的方案数。举个例子,从 (1, 2, 3) 三个物品中选择两个物品可以有 (1, 2),(1, 3),(2, 3) 这三种选择方法。
根据组合数的定义,我们可以给出计算组合数的一般公式:
C(n,m) = {n!}/{m!(n - m)!}
小葱想知道如果给定 n,m 和 k,对于所有的 0 ≤ i ≤ n, 0 ≤ j ≤ min(i,m) 有多少对 (i, j) 满足C(i.j)是 k 的倍数。
输入描述:
第一行有两个整数 t,k,其中 t 代表该测试点总共有多少组测试数据,k 的意义见 「题目描述」。
接下来 t 行每行两个整数 n,m,其中 n,m 的意义见「题目描述」。
输出描述:
t 行,每行一个整数代表对于所有的 0 ≤ i ≤ n, 0 ≤ j ≤ min(i,m) 有多少对 (i, j) 满足C(i,j)是 k 的倍数。
示例1
输入
1 2
3 3
输出
1
示例2
输入
2 5
4 5
6 7
输出
0
7
说明
在所有可能的情况中,只有C(2,1)=2是 2 的倍数。
备注:
3 ≤ n, m ≤ 2000, 2 ≤ k ≤ 21, 1 ≤ t ≤ 10000
解题思路:
由题目可知,可采用预处理的方式对c[i][j]数组处理,当从i个物品中选中j个物品,即c[i][j],等于第i个物品被选中时即c[i-1][j-1]+第i个物品未被选中即c[i-1][j]; 即c[i][j]=c[i-1][j-1]+c[i-1][j];
1)先对c[][]进行初始化
c[0][0]=0;
c[1][1]=1;
- 在主函数中用c[][]数组同时来统计c[i][j]=0的个数,可求得每次从i个物品选出(0~min(i,m))的方法的总个数。
for(int i=1;i<=2000;i++)//统计个数
{
for(int j=0;j<=i;j++)
{ if(!c[i][j])
{
if(j) c[i][j]=c[i][j-1]+1;
else c[i][j]=1;
}
else
{
if(j) c[i][j]=c[i][j-1];
else c[i][j]=0;
}
}
}
源代码:
#include <iostream>
#include <bits/stdc++.h>
#include <cmath>
#define eps 1e-4
using namespace std;
// 排列组合问题
const int maxn=2100;
int k;
int c[maxn][maxn]={0};
void yu()
{
c[0][0]=0;
c[1][1]=1;
for(int i=1;i<=2000;i++)
{
for(int j=0;j<=i;j++)
{
if((j==0)||(i==j))
{
c[i][j]=1,c[i][j]%=k;
}
else
{
c[i][j]=c[i-1][j-1]+c[i-1][j];
c[i][j]%=k;
}
}
}
}
int main()
{
int t,n,m;
cin>>t>>k;
yu();
for(int i=1;i<=2000;i++)//统计个数
{
for(int j=0;j<=i;j++)
{ if(!c[i][j])
{
if(j) c[i][j]=c[i][j-1]+1;
else c[i][j]=1;
}
else
{
if(j) c[i][j]=c[i][j-1];
else c[i][j]=0;
}
}
}
for(int i=1;i<=t;i++)
{
int sum=0;
cin>>n>>m;
for(int j=1;j<=n;j++)
{
sum+=c[j][min(j,m)];
}
cout<<sum<<endl;
}
return 0;
}