P3455 [POI2007]ZAP-Queries

题意翻译

题目描述

密码学家正在尝试破解一种叫 BSA 的密码。

他发现,在破解一条消息的同时,他还需要回答这样一种问题:

给出 a,b,d,求满足 1≤x≤a1,1≤y≤b1,且 gcd⁡(x,y)=d 的二元组 (x,y) 的数量。

因为要解决的问题实在太多了,他便过来寻求你的帮助。

输入格式

输入第一行一个整数 n,代表要回答的问题个数。

接下来 n 行,每行三个整数 a,b,d

输出格式

对于每组询问,输出一个整数代表答案。

数据范围

1≤n≤500001 1≤d≤a,b≤50000

输入输出样例

输入 #1

2
4 5 2
6 4 3

输出 #1

3
2

一句话题意 求(displaystyle sum_{i=1}^nsum_{j=1}^m[gcd(i , j) = d])

其中 d 给定

化简一下式子

(large displaystyle sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=d])

=(large displaystyle sum_{i=1}^{leftlfloorfrac{a}{d} ight floor}sum_{j=1}^{leftlfloorfrac{b}{d} ight floor}[gcd(i,j) = 1])

=(displaystyle sum_{i=1}^{leftlfloorfrac{a}{d} ight floor}sum_{j=1}^{leftlfloorfrac{b}{d} ight floor}sum_{p | i , j}mu(p))

=(displaystyle sum_{p=1}^{leftlfloorfrac{a}{d} ight floor} mu(p)sum_{i=1}^{leftlfloorfrac{a}{dp} ight floor}sum_{j=1}^{leftlfloorfrac{b}{dp} ight floor} 1)

到这基本就完了 , 对a , b 一起整除分块 , 在对mu[p] 求个前缀和。就没了

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 5e4+100;
#define int long long
int tot;
int vis[N] , prime[N] , mu[N];
long long sum[N];
void Init()
{
	int maxn = 5e4;
	mu[1] = 1; sum[1] = 1;
	for(int i = 2 ; i <= maxn ; ++i)
	{
		if(!vis[i]) { prime[++tot] = i; mu[i] = -1; }
		for(int j = 1 ; j <= tot && i * prime[j] <= maxn ; ++j)
		{
			vis[i * prime[j]] = 1;
			if(i % prime[j]) mu[i*prime[j]] = -mu[i];
			else { mu[i*prime[j]] = 0; break; }
		
		}
		sum[i] = sum[i-1] + mu[i];
	}
	return ;
}

signed main()
{
	Init();
	int n , a , b , d; scanf("%lld" ,&n);
	while(n --)
	{
		scanf("%lld%lld%lld",&a,&b,&d); a /= d; b /= d;
		if(a > b) swap(a , b);
		long long ans = 0;
		for(int p = 1 , r ; p <= a ; p = r + 1)
		{
			r = min(a , min(a / (a / p) , b / (b / p)));
			ans = ans + (sum[r] - sum[p-1]) * (a / p) * (b / p); // a / p & b / p 是整除 
		}
		printf("%lld
" , ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12164670.html