HYSBZ - 2301 Problem b(快速枚举除法取值)

题目:

对于给出的 n 个询问,每次求有多少个数对 (x,y) ,满足 a ≤ x ≤ b , c ≤ y ≤ d ,且gcd(x,y) = k , gcd(x,y) 函数为 x 和 y 的最大公约数。Input

第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k

Output

共n行,每行一个整数表示满足要求的数对(x,y)的个数

Sample Input22 5 1 5 11 5 1 5 2

Sample Output

14
3

Hint

100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000


思路:

首先把问题化简成,求有多少个数对(x,y)满足1<=x<=n,1<=y<=m且gcd(x,y)=1


这里我们只需要求f(1)即可

优化的关键是快速枚举除法取值,太厉害了

代码:

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;

const int N = 50000;
bool prime[N];
int u[N], su[N];//su是u的前缀和

void getu()
{
	for (int i = 0; i < N; i++)prime[i] = true, u[i] = 1;
	prime[1] = false;
	for (int i = 2; i < N; i++)if (prime[i])for (int j = 1; i* j < N; j++)
		prime[i*j] = false, u[i*j] *= -1 * (j%i != 0);
	su[0] = u[0];
	for (int i = 1; i < N; i++)su[i] = su[i - 1] + u[i];
}

int f(int n, int m)//有多少个数对(x,y)满足1<=x<=n,1<=y<=m且gcd(x,y)=1
{
	int res = 0;
	for (int i = 1, key; i <= n && i <= m; i = key + 1)
	{
		key = min(n / (n / i), m / (m / i));
		res += (n / i)*(m / i)*(su[key] - su[i - 1]);
	}
	return res;
}

int main()
{
	int n, a, b, c, d, k;
	scanf("%d", &n);
	getu();
	while (n--)
	{
		scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
		a--, c--;
		a /= k, b /= k, c /= k, d /= k;
		printf("%d\n", f(b, d) - f(a, d) - f(b, c) + f(a, c));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/nameofcsdn/article/details/80218498
今日推荐