问题描述
给
n
,
m
,
k
n,m,k
n,m,k,求有多少对
(
i
,
j
)
(i,j)
(i,j)满足
1
≤
i
≤
n
1≤i≤n
1≤i≤n,
0
≤
j
≤
m
i
n
(
i
,
m
)
0≤j≤min(i,m)
0≤j≤min(i,m)且
C
i
j
=
0
(
m
o
d
C_i^j=0(mod
Cij=0(mod
k
)
k)
k),
k
k
k是质数。其中
C
i
j
C_i^j
Cij是组合数,表示从
i
i
i个不同的数中选出
j
j
j个组成一个集合的方案数。
【样例输入】
1 2
3 3
【样例输出】
1
【样例说明】
在所有可能的情况中,只有
C
2
1
=
2
C_2^1=2
C21=2是
2
2
2的倍数
题目解析
式子
C
i
j
=
0
(
m
o
d
C_i^j=0(mod
Cij=0(mod
k
)
k)
k)意思是
C
i
j
C_i^j
Cij能整除
k
k
k。因此题目就是在求解满足
1
≤
i
≤
n
1≤i≤n
1≤i≤n,
0
≤
j
≤
m
i
n
(
i
,
m
)
0≤j≤min(i,m)
0≤j≤min(i,m)的所有
C
i
j
C_i^j
Cij中,能整除
k
k
k的个数。
计算
C
i
j
C_i^j
Cij公式如下:
C
i
j
=
i
!
j
!
×
(
i
−
j
)
!
C_i^j=\frac{i!}{j!×(i-j)!}
Cij=j!×(i−j)!i!
由于阶乘增长很快,我们可以利用递推式:
C
(
i
,
j
)
=
C
(
i
−
1
,
j
−
1
)
+
C
(
i
−
1
,
j
)
C(i,j)=C(i-1,j-1)+C(i-1,j)
C(i,j)=C(i−1,j−1)+C(i−1,j)
C++代码
#include<bits/stdc++.h>
using namespace std;
const int Mod=1e9+7;
int c[2010][2010]; //记录组合数c[n][m]
int main()
{
int n,m,t,k;
cin>>t>>k;
int nn=2000,mm=2000; //小规模问题
for(int i=0;i<=nn;i++)
{
c[i][0]=1;
c[i][i]=1;
}
for(int i=1;i<=nn;i++) //提前计算出所有的组合数
for(int j=1;j<=mm;j++)
c[i][j] = (c[i-1][j-1]+c[i-1][j])%k; //直接对k取余
while(t--)
{
cin>>n>>m;
int ans=0;
for(int j=0;j<=m;j++)
for(int i=j;i<=n;i++)
if(c[i][j]==0) ans++;
cout<<ans%Mod;
}
return 0;
}