3062: 【普及+/提高】【P2822】组合数问题

内存限制:512 MB 时间限制:2.000 S
评测方式:文本比较 命题人:
提交:11 解决:2

题目描述

组合数 $\binom{n}{m}$ 表示的是从 $n$ 个物品中选出 $m$ 个物品的方案数。举个例子,从 $(1,2,3)$ 三个物品中选择两个物品可以有 $(1,2),(1,3),(2,3)$ 这三种选择方法。根据组合数的定义,我们可以给出计算组合数 $\binom{n}{m}$ 的一般公式: $$\binom{n}{m}=\frac{n!}{m!(n-m)!}$$ 其中 $n!=1\times2\times\cdots\times n$;特别地,定义 $0!=1$。 小葱想知道如果给定 $n,m$ 和 $k$,对于所有的 $0\leq i\leq n,0\leq j\leq \min \left ( i, m \right )$ 有多少对 $(i,j)$ 满足 $k|\binom{i}{j}$。

输入

第一行有两个整数 lns="http://www.w3.org/1998/Math/MathML">,,其中 lns="http://www.w3.org/1998/Math/MathML"> 代表该测试点总共有多少组测试数据,lns="http://www.w3.org/1998/Math/MathML"> 的意义见问题描述。

接下来 lns="http://www.w3.org/1998/Math/MathML"> 行每行两个整数 lns="http://www.w3.org/1998/Math/MathML">,,其中 lns="http://www.w3.org/1998/Math/MathML">, 的意义见问题描述。

输出

共 lns="http://www.w3.org/1998/Math/MathML"> 行,每行一个整数代表所有的 lns="http://www.w3.org/1998/Math/MathML">0,0min(,) 中有多少对 lns="http://www.w3.org/1998/Math/MathML">(,) 满足 lns="http://www.w3.org/1998/Math/MathML">()

样例输入 复制

1 2
3 3

样例输出 复制

1

提示


输入 #2
2 5
4 5
6 7
输出 #2
0
7


【样例1说明】

在所有可能的情况中,只有 lns="http://www.w3.org/1998/Math/MathML">(21)=2 一种情况是 lns="http://www.w3.org/1998/Math/MathML">2 的倍数。

【子任务】

  • 对于全部的测试点,保证 lns="http://www.w3.org/1998/Math/MathML">0,2×103lns="http://www.w3.org/1998/Math/MathML">1104



#include<bits/stdc++.h>
using namespace std;
const int N = 2010;  //n的数值上限
long long C[N][N]; 
int main(){
    int t,k,m,n;
    cin>>t>>k;
    for(int i=0;i< N;i++) {
    	C[i][0]=C[i][i]=1;
    	for(int j=1;j<i;j++) 
    	    C[i][j]=(C[i-1][j]+C[i-1][j-1])%k; //递推			 
	}
	while(t--) {
		int ans=0;
		cin>>n>>m;
		for(int i=0;i<=n;i++)
		    for(int j=0;j<=min(i,m);j++)
		        ans+=C[i][j]==0;
		cout<<ans<<endl;
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int N = 2010;  //n的数值上限
int C[N][N];
int s[N][N]; //二维前缀和
int main(){
    //默认初始值-1,之所以初始为-1,是怕默认的0无法描述是模完变成的0,还是天生默认就是0,-1就有这个好处。
    memset(C, -1, sizeof C);
    int t,k,m,n;
    cin>>t>>k;
    for(int i=0;i<N;i++) {
    	C[i][0]=C[i][i]=1;
    	for(int j=1;j<i;j++) 
    	    C[i][j]=(C[i-1][j]+C[i-1][j-1])%k; //递推			 
	}
    for (int i = 1; i < N; i++) //标准的二维前缀和
        for (int j = 1; j < N; j++)
            s[i][j] = (C[i][j] == 0 ? 1 : 0) + s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1];
    while (t--) { //处理t次询问
        cin >> n >> m;
        cout << s[n][m] << endl;
    }
	return 0;
}