[NOIP2016]组合数问题——排列组合问题

链接: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;
  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;
}



上一篇:【NOIP2016提高A组模拟9.9】Brothers 题解


下一篇:【题解】[NOIP2016 提高组] 天天爱跑步