NOIP2016 组合数问题

难度:普及+

题目类型:数论、模拟

提交次数:-

涉及知识:预处理、前缀和、组合数

题目描述

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

其中n! = 1 × 2 × · · · × n

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

输入输出格式

输入格式:

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

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

输出格式:

t行,每行一个整数代表答案。

输入输出样例

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

代码:
 1 #include<iostream>
 2 using namespace std;
 3 int a[2010][2010];
 4 int modk[2010];
 5 int t, k;
 6 int main(){
 7     cin>>t>>k;
 8     //预处理
 9     int i, j;
10     for(i = 1; i<= 2000; i++)
11         a[i][1] = 1;
12     for(i = 1; i<= 2000; i++){
13         modk[i] += modk[i-1];
14         for(j = 2; j <= i; j++){
15             a[i][j] = (a[i-1][j]%k + a[i-1][j-1]%k)%k;
16             if(a[i][j]%k==0) modk[i]++;
17         }
18     } 
19 /*    for(i = 1; i<= 10; i++){
20         for(j = 1; j <= i; j++){
21             cout<<a[i][j]<<" ";
22         }
23         cout<<endl;
24     }
25     for(i = 1; i<= 20; i++){
26         cout<<modk[i]<<endl;
27     }*/
28     while(t--){
29         int n, m;
30         cin>>n>>m;
31         int ans = 0;
32         for(j = 1; j <= min(m,n); j++){
33             if(a[n+1][j]%k==0) ans++;
34         }
35         ans += modk[n];
36         cout<<ans<<endl;
37     }
38     return 0;
39 }

备注:

去年比赛day1第一题。拿了50。T的取值范围是10的四次方,计算组合数的复杂度是n*m,肯定爆了。。。

预处理+前缀和。前缀和就是每一行(n确定)累加下去。。

然后就满了。

果然当时还是图样。

 
原文地址:https://www.cnblogs.com/fangziyuan/p/6568479.html