组合数

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

const int MAXN=2000,MAXM=2000;

int t,k,table[MAXM][MAXN],ser[MAXM][MAXN],h[MAXN];
//table数组用来打杨辉三角表(边打表边取余)
//取余公式非常简单 (a+b)%c=((a%c)+(b%c))%c;
//ser数组用来存储C(j,i)范围内的可以整除k的个数
//k数组用于动态的存储当前行里有多少个满足条件的C(j,i)
//简单介绍杨辉三角
//n\m 0 1 2  3  4  5 6
//0   1
//1   1 1
//2   1 2 1
//3   1 3 3  1
//4   1 4 6  4  1
//5   1 5 10 10 5  1 
//6   1 6 15 20 15 6 1
//上面的横排是C(m,n)中的m
//竖排是C(m,n)中的n
//于是我们可以很简单用一个矩阵+dp求出所有的组合数
//满足公式C(m,n)=C(m,n-1)+C(m-1,n-1)
//当然接下来我的代码忽略了m=0和n=0的情况 
int main(){
    cin>>t>>k;
    //预处理开始 
    for(int i=0;i<MAXM;++i){
        for(int j=0;j<i;++j){//复杂度O( n(n-1)m/2 ) n是MAXN,m是操作步数
            if(j==0){//第一竖行都是i+1 我直接单独处理 
                table[i][j]=(i+1)%k;//杨辉三角的dp求解 
                if(!table[i][j]){
                    ++h[i];//如果满足整除k 就记录在h中
                }
                ser[i][j]=ser[i-1][j]+h[i];//这里dp出C(1,1)到C(i,j)有多少个满足条件的组合数 
                //cout<<ser[i][j]<<" ";
                continue;
            }
            table[i][j]=(table[i-1][j]+table[i-1][j-1])%k; //杨辉三角的dp求解 
            if(!table[i][j]){
                ++h[i];//如果满足整除k 就记录在h中
            }
            ser[i][j]=ser[i-1][j]+h[i];//这里dp出C(1,1)到C(i,j)有多少个满足条件的组合数 
            //cout<<ser[i][j]<<" ";
        }
        //对于C(i,i)也就是j=i的情况单独处理 一定是1 
        table[i][i]=1%k;
        if(i==0&&!table[0][0]){
            ++ser[0][0];
            continue;
        }
        ser[i][i]+=ser[i][i-1];
        if(!table[i][i]){
            ++ser[i][i];
        }
        //cout<<ser[i][i]<<endl;
    }
    for(int i=0;i<t;++i){//查询操作直接O(1)完成 
        int n,m;
        cin>>n>>m;
        --n,--m;
        if(m>n)m=n;//注意m可能大于n 
        cout<<ser[n][m]<<endl; 
    } 
    return 0;
}

 

转载于:https://www.cnblogs.com/voldemorte/p/7234794.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值