解题思路
由于要求对k取模为0的值,所以我们递推求组合数时一直对k取模就行了
然后算出二维前缀和,O(n^2)预处理,O(1)回答。BZOJ上和这个不太一样,
那个是要卢卡斯定理。
代码
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN = 2005;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int n,m,t,k;
LL ans[MAXN][MAXN];
LL C[MAXN][MAXN];
int main(){
t=rd();k=rd();
C[1][0]=1;C[1][1]=1;C[0][0]=1;
for(register int i=2;i<=MAXN;i++){
C[i][0]=1;
for(register int j=1;j<=i;j++){
C[i][j]=(C[i-1][j]+C[i-1][j-1])%k;
ans[i][j]=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1];
if(C[i][j]==0) ans[i][j]++;
// cout<<i<<" "<<j<<" "<<ans[i][j]<<endl;
}
ans[i][i+1]=ans[i][i]; //注意此处,因为ans[i][j]要被
} //ans[i-1][j]更新,当i=j时i比j小
for(register int i=1;i<=t;i++){
n=rd();m=rd();
if(m>n) m=n;
printf("%lld
",ans[n][m]);
}
return 0;
}