A: 组合数问题
时间限制: 1 Sec 内存限制: 512 MB题目描述
组合数C(n,m)表示的是从
n
个物品中选出
m
个物品的方案数。举个例子,从
(1, 2, 3)
三个物品中选择两个物品可以有
(1, 2),(1, 3),(2, 3)
这三种选择方法。根据组合数的定义,我们可以给出计算组合数C(n,m)的一般公式:
C(n,m)=n!/(m!(n-m)!)
其中
n
!
=
1
×
2
×···×
n。
小葱想知道如果给定
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 2
3 3
2 5
4 5
6 7
样例输出
1
0
7
提示
【样例 1 说明】
在所有可能的情况中,只有C(2,1)=2 是2的倍数。
【子任务】
测试点
|
n
|
m
|
k
|
t
|
1
|
≤
3
|
≤
3
|
=
2
|
=
1
|
2
|
=
3
|
≤
104
| ||
3
|
≤
7
|
≤
7
|
=
4
|
=
1
|
4
|
=
5
|
≤
104
| ||
5
|
≤
10
|
≤
10
|
=
6
|
=
1
|
6
|
=
7
|
≤
104
| ||
7
|
≤
20
|
≤
100
|
=
8
|
=
1
|
8
|
=
9
|
≤
104
| ||
9
|
≤
25
|
≤
2000
|
=
10
|
=
1
|
10
|
=
11
|
≤
104
| ||
11
|
≤
60
|
≤
20
|
=
12
|
=
1
|
12
|
=
13
|
≤
104
| ||
13
|
≤
100
|
≤
25
|
=
14
|
=
1
|
14
|
=
15
|
≤
104
| ||
15
|
≤
60
|
=
16
|
=
1
| |
16
|
=
17
|
≤
104
| ||
17
|
≤
2000
|
≤
100
|
=
18
|
=
1
|
18
|
=
19
|
≤
104
| ||
19
|
≤
2000
|
=
20
|
=
1
| |
20
|
=
21
|
≤
104
|
我们可以先求出C(i,j)的值。通过找规律可以发现这是一个杨辉三角。可以求出记为f[i,j]并 mod k。然后记dp[i,j]为C(i,j)的个数。当f[i,j]=0时,dp[i,j]=dp[i,j-1]+1,否则dp[i,j]=dp[i,j-1]。最后每组从1到m循环一遍求解即可。
Code:
var
t,k,i,j,ans,n,m:longint;
dp,f:array[0..2000,0..2000] of longint;
begin
readln(t,k);
for i:=0 to 2000 do f[i,0]:=1;
for i:=1 to 2000 do
for j:=1 to i do
f[i,j]:=(f[i-1,j]+f[i-1,j-1]) mod k;
for i:=1 to 2000 do
for j:=1 to i do
if f[i,j]=0 then
dp[i,j]:=dp[i,j-1]+1 else
dp[i,j]:=dp[i,j-1];
for i:=1 to t do
begin
ans:=0;
readln(n,m);
for j:=1 to n do
if j>m then ans:=ans+dp[j,m]
else ans:=ans+dp[j,j];
writeln(ans);
end;
end.