题目描述
我们高中曾经学过何为组合数。 那么,给出整数n,m,g,聪明的你能否求出有多少整数对(i,j),满足g整除吗?(其中0≤i≤n,0≤j≤min(i,m))。 (提示:n!=1×2×⋯×n;特别地,0!=1。)
输入
第一行一个整数T(T<=104 ),表示测试数据的组数;
第二行一个整数g(1<g<=25);
接下来T行每行两个整数n,m(n,m<=2000);
n,m,g的意义见题目描述。
输出
输出T行,每行一个整数,表示有多少对整数对(i,j)满足g整除(0≤i≤n,0≤j≤min(i,m))。
样例输入 Copy
1 4 5 4
样例输出 Copy
2
题目分析:比较简单的一道题,但比赛的时候被题面和题目吓到了,就去做别的题了,也没有花时间思考,放过了一道签到题,首先这个题目的切入点是 n 和 m 都小于 2000 ,也就是说可以预处理打表出 C[ i ][ j ] ,因为对于每个样例而言,其 mod 都是一样的,所以在预处理组合数时,可以使用这个 mod ,比赛读题的时候还以为是 mod % C[ i ][ j ] == 0 作为判断条件,结果补题的时候发现自己读错题了,既然是C[ i ][ j ] % mod == 0 为判断条件,那么就可以维护一个二维矩阵 maze[ i ][ j ] 用来储存点C[ i ][ j ]是否能被整除,因为询问比较大,所以我们可以维护一个二维前缀和,这样就能O(1)查询了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=2e3+100;
int C[N][N],mod,maze[N][N];
void init()
{
for(int i=1;i<N;i++)
for(int j=1;j<=i;j++)
{
if(j==1)
C[i][j]=i%mod;
else
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
if(!C[i][j])
maze[i][j]++;
}
for(int i=1;i<N;i++)
for(int j=1;j<N;j++)
maze[i][j]+=maze[i][j-1]+maze[i-1][j]-maze[i-1][j-1];
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int w;
cin>>w>>mod;
init();
while(w--)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",maze[x][y]);
}
return 0;
}