落谷 P3455 ZAP-Queries(莫比乌斯反演入门题+分块)

####题目链接:https://www.luogu.org/problem/P3455
P3455 [POI2007]ZAP-Queries
提交 4.14k
通过 2.32k
时间限制 2.00s
内存限制 125.00MB
题目提供者 洛谷
难度
省选/NOI-
历史分数 100
提交记录 查看题解
标签
POI
高性能
2007
相关讨论
进入讨论版
推荐题目
展开
题目描述

Byteasar the Cryptographer works on breaking the code of BSA (Byteotian Security Agency). He has alreadyfound out that whilst deciphering a message he will have to answer multiple queries of the form"for givenintegers aaa, bbb and ddd, find the number of integer pairs (x,y)(x,y)(x,y) satisfying the following conditions:

1≤x≤a1\le x\le a1≤x≤a,1≤y≤b1\le y\le b1≤y≤b,gcd(x,y)=dgcd(x,y)=dgcd(x,y)=d, where gcd(x,y)gcd(x,y)gcd(x,y) is the greatest common divisor of xxx and yyy".

Byteasar would like to automate his work, so he has asked for your help.

TaskWrite a programme which:

reads from the standard input a list of queries, which the Byteasar has to give answer to, calculates answers to the queries, writes the outcome to the standard output.

FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。
输入格式

The first line of the standard input contains one integer nnn (1≤n≤50 0001\le n\le 50\ 0001≤n≤50 000),denoting the number of queries.

The following nnn lines contain three integers each: aaa, bbb and ddd(1≤d≤a,b≤50 0001\le d\le a,b\le 50\ 0001≤d≤a,b≤50 000), separated by single spaces.

Each triplet denotes a single query.
输出格式

Your programme should write nnn lines to the standard output. The iii’th line should contain a single integer: theanswer to the iii’th query from the standard input.
输入输出样例
输入 #1

2
4 5 2
6 4 3

输出 #1

3
2


分析:

与hdu 1695类似 hdu 1695题解
最后得分块,hdu 1695不分块也会过,但这题不分块会超时。首先预处理下前n个mob[i]的的和。然后就是分块。学到了两个变量的分块,具体看代码:

代码:

	#include 

using namespace std;
#define ll long long 
#define fr first
#define sc second

const int N=5e4+5;
int prime[N+1];
int mob[N+1];
ll sum[N+1];

void Mobius()
{
	memset(prime,0,sizeof(prime));
	mob[1]=1;
	sum[1]=1;
	for(int i=2;i<=N;i++)
	{
		if(!prime[i])
		{
			prime[++prime[0]]=i;
			mob[i]=-1;
		}
		for(int j=1;j<=prime[0]&&i*prime[j]<=N;j++)
		{
			prime[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				mob[i*prime[j]]=0;
				break;
			}
			mob[i*prime[j]]=-mob[i];
		}
		sum[i]=sum[i-1]+mob[i];
	}
}


int main()
{
	Mobius();
	int t,a , b, d;
	ll ans;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d",&a,&b,&d);
		ans=0;
		a/=d,b/=d;
		int tmp = min(a,b);
		// for(int i=1;i<=tmp;i++) ans +=mob[i]*(a/i)*(b/i);
		//上面的超时了,得分块
		for(int l=1,r;l<=tmp;l=r+1)
		{
			r=min(a/(a/l),b/(b/l));// 对于两个变量,还可以这样分块,学到了
			ans += 1LL*(sum[r]-sum[l-1])*(a/l)*(b/l);
		}
		printf("%d\n",ans);
		
	}

	return 0;
}

你可能感兴趣的:(莫比乌斯反演)