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;
}
posted @ 2020-12-16 17:07  肆之月  阅读(73)  评论(0编辑  收藏  举报