H y p e r l i n k Hyperlink Hyperlink
https://www.luogu.com.cn/problem/P2822
D e s c r i p t i o n Description Description
给定
T
T
T组数据和一个数
k
k
k,每组数据给定一个
n
,
m
n,m
n,m,要求回答
∑
i
=
1
n
∑
j
=
1
m
i
n
(
n
,
m
)
[
C
i
j
m
o
d
k
=
=
0
]
\sum _{i=1}^n \sum_{j=1}^{min(n,m)} [C_i^j\mod k==0]
i=1∑nj=1∑min(n,m)[Cijmodk==0]
数据范围: n , m ≤ 3 × 1 0 3 , T ≤ 1 0 4 , k ≤ 21 n,m\leq 3\times 10^3,T\leq 10^4,k\leq 21 n,m≤3×103,T≤104,k≤21
S o l u t i o n Solution Solution
利用组合数公式
C
i
j
=
C
i
−
1
j
−
1
+
C
i
−
1
j
C_i^j=C_{i-1}^{j-1}+C_{i-1}^j
Cij=Ci−1j−1+Ci−1j预处理
C
C
C对
k
k
k取模的结果
用二维前缀和保存其为0的情况即可
时间复杂度: O ( n 2 + T ) O(n^2+T) O(n2+T)
C o d e Code Code
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;int T,n,m,k,C[2010][2010],s[2010][2010];
inline LL read()
{
char c;LL d=1,f=0;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
signed main()
{
T=read();k=read();
C[0][0]=1;C[1][0]=1;C[1][1]=1;
for(register int i=2;i<=2000;i++)
{
C[i][0]=1;
for(register int j=1;j<=i;j++)
{
C[i][j]=(C[i-1][j-1]+C[i-1][j])%k;
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+(C[i][j]==0);
}
s[i][i+1]=s[i][i];
}
while(T--)
{
n=read();m=read();
if(m<=n) printf("%d\n",s[n][m]);
else printf("%d\n",s[n][n]);
}
}