NOIP 2016 Day2 T1 组合数问题

题意概述

给定组合数公式

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

是k的倍数。

输入格式

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

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

输出格式

t行,每行一个整数代表所有的0 <= i <= n, 0 <= j <= min(i, m)有多少对(i, j)满足CijC_i^jCij​​是k的倍数。

样例1

样例输入1

1 2
3 3

样例输出1

1

样例2

样例输入2

2 5
4 5
6 7

样例输出2

0
7

 

 题解

这是一道明显的数论题,那么画一画即可得到组合数的递推式
其实也是可以证明的,但是不在这里赘述了。


那么因为n,m都是小于2000的,并且对于每一个测试点,k是不变的。所以预处理出2000以内的个数,然后根据输入的n,m统计就好了

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 int a[2005][2005], tj[2005][2005];
 7 int n, m, ans, t, k;
 8 int main()
 9 {
10     scanf("%d%d",&t,&k);
11     memset(a,0,sizeof(a));
12     a[1][1] = 1 % k;
13     if (a[1][1] == 0) tj[1][1]++;
14     for (int j=2; j<=2001; j++)
15          for (int q = 1; q <= min(j, 2001); q++)
16         {
17              if (q == 1) a[j][q] = (a[j-1][q] + 1) % k;
18               else a[j][q] = (a[j-1][q] + a[j-1][q-1])%k;
19               if (a[j][q] == 0) tj[j][q] = tj[j][q-1]+1; 
20             else tj[j][q] = tj[j][q-1];
21         }
22     for (int i=1; i<=t; i++)
23     {
24         scanf("%d%d",&n, &m);
25         ans = 0;
26         for (int j=1; j<=n; j++)
27              ans += tj[j][min(m,j)];
28         printf("%d
", ans);
29     }
30     return 0;      
31 }
原文地址:https://www.cnblogs.com/Droyal/p/7154181.html