P2822 组合数问题

小葱想知道如果给定 n,m 和 k,对于所有的 0≤i≤n,0≤j≤min(i,m) 有多少对 (i,j)(i,j) 满足 Ci取j 是 k 的倍数。

输入格式:

第一行有两个整数 t,kt,k,其中 tt 代表该测试点总共有多少组测试数据,k 的意义见问题描述。

接下来 tt 行每行两个整数 n,m,其中 n,m 的意义见问题描述。

输出格式:

共 t行,每行一个整数代表所有的0≤i≤n,0≤j≤min(i,m) 中有多少对 (i,j)(i,j) 满足Ci取j是 k 的倍数。

输入样例#1:
1 2
3 3
输出样例#1:
1
输入样例#2:
2 5
4 5
6 7
输出样例#2:
0
7

dp[n][m]即为所求答案的意思,则有公式:
dp[i][j]=dp[i-1][j]+f[i][j] f[i][j]=C(i,k)% k==0的个数,0<=k<=j
又有f[i][j]=f[i][j-1]+(C(i,j)%k ==0 ),
C[i][j]=(c[i-1][j-1]+c[i]-1[j])%k , 因为a=b+c, a%k=(b%k+c%k)%k
一题三个dp。。。。

#include<bits/stdc++.h>
using namespace std;
char buf[1<<17],*L=buf,*R=buf;
inline char gc() {
    return L==R&&(R=(L=buf)+fread(buf,1,1<<17,stdin),L==R)?EOF:*L++;
}
template<typename T>
inline void read(T&x) {
    int flag=x=0;
    char ch=gc();
    while (ch<'0'||ch>'9')
        flag|=ch=='-',ch=gc();
    while (ch>='0'&&ch<='9')
        x=(x<<3)+(x<<1)+ch-48,ch=gc();
    if(flag)
        x=-x;
}
const int MAXN=2e3+3;
int dp[MAXN][MAXN],f[MAXN][MAXN],c[MAXN][MAXN];
int t,k;
int main() {
    freopen("in.txt","r",stdin);
    read(t),read(k);
    c[0][0]=1%k;
    for(int i=1; i<MAXN; ++i) {
        c[i][0]=1%k;
        for(int j=1; j<=i; ++j) {
            c[i][j]=(c[i-1][j-1]+c[i-1][j])%k;
        }
    }
    f[0][0]=(c[0][0]==0);
    for(int i=1; i<MAXN; ++i) {
        f[i][0]=(c[i][0]==0);
        for(int j=1; j<MAXN; ++j) {
            if(j>i)
                f[i][j]=f[i][j-1];
            else
                f[i][j]=f[i][j-1]+(c[i][j]==0);
        }
    }
    dp[0][0]=f[0][0];
    for(int i=1; i<MAXN; ++i) {
        for(int j=0; j<MAXN; ++j) {
            dp[i][j]=dp[i-1][j]+f[i][j];
        }
    }
    int x,y;
    while(t--) {
        read(x),read(y);
        printf("%d\n",dp[x][y]);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值