洛谷P3455 [POI2007][BZOJ1101]ZAP-Queries
题目
Description
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 , and , find the number of integer pairs satisfying the following conditions:
, where is the greatest common divisor of and ".
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正在破解一段密码,他需要回答很多类似的问题:对于给定的整数 , 和 ,有多少正整数对 , ,满足 , ,并且 。作为FGD的同学,FGD希望得到你的帮助。
Input
The first line of the standard input contains one integer ( ),denoting the number of queries.
The following lines contain three integers each: , and ( ), separated by single spaces.
Each triplet denotes a single query.
Output
Your programme should write lines to the standard output. The 'th line should contain a single integer: theanswer to the 'th query from the standard input.
Sample Input
2
4 5 2
6 4 3
Sample Output
3
2
HINT
对于第一组询问,满足条件的整数对有 。对于第二组询问,满足条件的整数对有 。
题解
由题可知,需要我们求
那我们可以令
。
此时,求解
即是求解
。
由莫比乌斯函数的性质可以知道
。
我们可以尝试把式子里的
换成
。
即
式子可变为:
又知
。
将和式前移,可得
再把形如
化简为
此时如果暴力计算,则复杂度为
,但是可以观察到
和
是有大量重复的,于是可以用到前面整除分块的知识。利用整除分块和
的前缀和相乘,可将复杂度优化到
。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 10;
int mu[maxn], prime[maxn], cnt = 0;
bool vis[maxn];
void init() {
mu[1] = 1;
for (int i = 2; i < maxn; i++) {
if (vis[i] == false) {
prime[cnt++] = i;
mu[i] = -1;
}
for (int j = 0; j < cnt && prime[j] * i < maxn; j++) {
vis[i * prime[j]] = true;
if (i%prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
} else {
mu[i * prime[j]] = -mu[i];
}
}
}
for (int i = 2; i < maxn; i++) {
mu[i] += mu[i - 1];
}
}
int solve(int a, int b) {
int ans = 0;
if (a > b) swap(a, b);
for (int l = 1, r; l <= a; l = r + 1) {
r = min(a/(a/l), b/(b/l));
ans += (mu[r] - mu[l - 1]) * (a/l) * (b/l);
}
return ans;
}
int main()
{
init();
int t, a, b, d;
scanf("%d", &t);
while (t--) {
scanf("%d %d %d", &a, &b, &d);
printf("%d\n", solve(a/d, b/d));
}
return 0;
}