中石油训练赛 - 数学问题(思维)

题目描述

我们高中曾经学过何为组合数。 那么,给出整数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;
}
发布了691 篇原创文章 · 获赞 27 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/104760841