Description
组合数C(n,m)表示的是从n个物品中选出m个物品的方案数。举个例子,从(1,2,3) 三个物品中选择两个物品可以有(1,2),(1,3),(2,3)这三种选择方法。根据组合数的定义,我们可以给出计算组合数的一般公式:
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的倍数。
Input
第一行有两个整数t,k,其中t代表该测试点总共有多少组测试数据。
接下来t行每行两个整数n,m。
Sample Input
2 5 4 5 6 7
Sample Output
0 7
题解:
对于组合数递推式C(i,j)=C(i-1,j)+C(i,j-1),即物品可以选或不选,两种情况加起来。预处理出来利用前缀和,最后再依次查询。
#include<iostream> #include<cmath> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=2010; int n,m,t,k; int f[maxn][maxn],ans[maxn][maxn]; int main() { cin>>t>>k; for(int i=1; i<=2002; i++) { f[i][i]=1,f[i][0]=1,ans[i][0]=0; for(int j=1; j<i; j++) { f[i][j]=(f[i-1][j]+f[i-1][j-1])%k; if(f[i][j]==0) ans[i][j]=1; ans[i][j]+=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1]; } ans[i][i]=ans[i][i-1]; } while(t--) { cin>>n>>m; cout<<ans[n][min(n,m)]<<endl; } return 0; }