组合数 前缀和 T3 todo 523. 组合数问题 - AcWing题库
组合数 表示的是从 个物品中选出 个物品的方案数。
举个例子,从 三个物品中选择两个物品可以有 , , 这三种选择方法。
根据组合数的定义,我们可以给出计算组合数 的一般公式:
其中 。
小葱想知道如果给定 和 ,对于所有的 有多少对 满足 是 的倍数。
输入格式
第一行有两个整数 ,其中 代表该测试点总共有多少组测试数据, 的意义见问题描述。
接下来 行每行两个整数 ,其中 的意义见问题描述。
输出格式
共 行,每行一个整数代表所有的 有多少对 满足 是 的倍数。
数据范围
输入样例:
1 2
3 3
输出样例:
1
思路
简单看一下题意, 给你一个 俩数, 求所有 的 是 的倍数的个数。
判断一个数是另一个数的倍数一般是通过取模运算 时, 说明 可以被 整除, 也就是 是 的倍数。
这里则是统计 的个数, 可以先用 递推计算 的值, 然后再前缀和统计所有取模后为0的值个数即可。
递推式原理是:, 而前缀和则是矩阵前缀和。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
using namespace std;
const int N = 2e3 +10;
int f[N][N];
int res[N][N];
int n,m,k;
void init()
{
for(int i = 0; i < N; i++)
{
for(int j = 0; j <= i; j++)
{
if(!j) f[i][j] = 1 % k;
else f[i][j] = (f[i - 1][j] + f[i - 1][j - 1]) % k;
if(!f[i][j]) res[i][j] = 1;
}
}
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
{
if(i) res[i][j] += res[i - 1][j];
if(j) res[i][j] += res[i][j - 1];
if(i && j) res[i][j] -= res[i - 1][j - 1];
}
}
int main()
{
int T;
cin >> T >> k;
init();
while(T--)
{
int n,m;
cin >> n >> m;
cout << res[n][m] << endl;
}
return 0;
}