组合数 前缀和 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;
}