• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
scorpiorax
博客园    首页    新随笔    联系   管理    订阅  订阅
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,对于所有的 0≤i≤n,0≤j≤min(i,m) 有多少对 (i,j) 满足 Cij​ 是 k 的倍数。

输入输出格式

输入格式:

 

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

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

 

输出格式:

 

共 t 行,每行一个整数代表所有的0≤i≤n,0≤j≤min(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("\n");
38     }
39     return 0;
40 }

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

posted on 2018-11-01 12:27  scorpiorax  阅读(169)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3