[HAOI2011]Problem b

Description
对于给出的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 Input
2
2 5 1 5 1
1 5 1 5 2

Sample Output
14
3

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


做这题前先看[POI2007]Zap,题解点这里。然后这题就相当于二维前缀和

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x>=10)     print(x/10);
	putchar(x%10+'0');
}
const int N=5e4;
int prime[N+10],miu[N+10],sum[N+10];
bool inprime[N+10];
void prepare(){
	miu[1]=1;
	int tot=0;
	for (int i=2;i<=N;i++){
		if (!inprime[i])	prime[++tot]=i,miu[i]=-1;
		for (int j=1;j<=tot&&i*prime[j]<=N;j++){
			inprime[i*prime[j]]=1;
			if (i%prime[j]==0){miu[i*prime[j]]=0;break;}
			miu[i*prime[j]]=-miu[i];
		}
	}
	for (int i=1;i<=N;i++)	sum[i]=sum[i-1]+miu[i];
}
ll work(int A,int B,int D){
	ll res=0;
	A/=D,B/=D;
	int x=min(A,B),pos=0;
	for (int d=1;d<=x;d=pos+1){
		pos=min(A/(A/d),B/(B/d));
		res+=1ll*(sum[pos]-sum[d-1])*(A/d)*(B/d);
	}
	return res;
}
int main(){
	prepare();
	for (int Data=read();Data;Data--){
		int a=read(),b=read(),c=read(),d=read(),k=read();
		ll Ans=work(b,d,k)-work(a-1,d,k)-work(b,c-1,k)+work(a-1,c-1,k);
		printf("%lld
",Ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Wolfycz/p/9481331.html