noip2016组合数问题

Posted rax-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了noip2016组合数问题相关的知识,希望对你有一定的参考价值。

题目描述

组合数 Cnm? 表示的是从 n 个物品中选出 m 个物品的方案数。举个例子,从 (1,2,3) 三个物品中选择两个物品可以有(1,2),(1,3),(2,3) 这三种选择方法。根据组合数的定义,我们可以给出计算组合数 Cnm? 的一般公式:

Cnm?=m!/(n?m)!n!?

其中n!=1×2×?×n;特别地,定义 0!=1。

小葱想知道如果给定 n,m 和 k,对于所有的 0in,0jmin(i,m) 有多少对 (i,j) 满足 Cij? 是 k 的倍数。

输入输出格式

输入格式:

 

第一行有两个整数 t,k,其中 t代表该测试点总共有多少组测试数据,k 的意义见问题描述。

接下来 t行每行两个整数 n,m,其中 n,m 的意义见问题描述。

 

输出格式:

 

共 t 行,每行一个整数代表所有的0in,0jmin(i,m) 中有多少对 (i,j) 满足 Cij? 是 k 的倍数。

 

输入输出样例

输入样例#1: 复制
1 2
3 3
输出样例#1: 复制
1
输入样例#2: 复制
2 5
4 5
6 7
输出样例#2: 复制
0
7

说明

【样例1说明】

在所有可能的情况中,只有C_2^1 = 2C21?=2是2的倍数。

【子任务】

技术分享图片

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 int i,j,n,m,t,k,ans[2005][2005],c[2005][2005];
 7 void build()
 8 {
 9     c[0][0] = 1;
10     c[1][0] = 1;
11     c[1][1] = 1;
12     for(i = 2;i <= 2000;i++)
13     {
14         c[i][0] = 1;
15         for(j = 1;j <= i;j++)
16         {
17             c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % k; //第j个选他的可能性和不选他的可能性加在一起 
18             ans[i][j] = ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1];//求前缀和 
19             if(c[i][j] == 0) //代表是k的倍数 
20             ans[i][j]++;
21             ans[i][i + 1] = ans[i][i]; //继承 
22         }
23     }
24 }
25 int main()
26 {
27     scanf("%d %d",&t,&k);
28     build();
29     for(i = 1;i <= t;i++)
30     {
31         scanf("%d %d",&n,&m);
32         if(n < m)
33         printf("%d",ans[n][n]);//在这种情况下最多也只能取到n 
34         else
35         printf("%d",ans[n][m]);
36         if(i != t)
37         printf("
");
38     }
39     return 0;
40 }

*******万恶的组合数,竟然还有前缀和这个操作。

以上是关于noip2016组合数问题的主要内容,如果未能解决你的问题,请参考以下文章

noip2016组合数问题

noip2016 组合数问题

NOIP2016组合数问题

NOIP2016 组合数问题

NOIP2016组合数问题

[NOIP2016提高组]组合数问题