题目描述
解题思路
这题一看数据范围就知道不能用普通方法做,所以我想到了杨辉三角,杨辉三角中
a
[
i
]
[
j
]
=
C
j
−
1
i
−
1
a[i][j]=C^{i-1}_{j-1}
a[i][j]=Cj−1i−1,并且如果边做边模就不会爆int,于是我交了一个杨辉三角,结果愉快地爆了
可见普通的杨辉三角加一次遍历是绝对会爆的,所以我又想到了答案前缀和,在计算当前这个数的时候就把前
i
,
j
i,j
i,j个数中符合答案的数的数量用前缀和记起来,这样就可以省略再次遍历的时间。
代码
#include<bits/stdc++.h>
using namespace std;
int a[2005][2005],ans[2005][2005];
int n,m,k,t;
void sj(){
a[0][0]=1;
a[1][0]=a[1][1]=1;
for(int i=2;i<=2000;i++){
a[i][0]=1;
for(int j=1;j<=i;j++){
a[i][j]=(a[i-1][j-1]+a[i-1][j])%k;
ans[i][j]=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1];//前缀和
if(a[i][j]==0) ans[i][j]++;
}
ans[i][i+1]=ans[i][i];
}
}
int main(){
cin>>t>>k;
sj();
for(int i=1;i<=t;i++){
cin>>n>>m;
m=min(n,m);
cout<<ans[n][m]<<endl;
}
return 0;
}