PGCD - Primes in GCD Table
Johnny has created a table which encodes the results of some operation – a function of two arguments. But instead of a boring multiplication table of the sort you learn by heart at prep-school, he has created a GCD (greatest common divisor) table! So he now has a table (of height a and width b), indexed from (1,1) to (a,b), and with the value of field (i,j) equal to gcd(i,j). He wants to know how many times he has used prime numbers when writing the table.
Input
First, t ≤ 10, the number of test cases. Each test case consists of two integers, 1 ≤ a,b < 107.
Output
For each test case write one number - the number of prime numbers Johnny wrote in that test case.
Example
Input:
2
10 10
100 100
Output:
30
2791
在之前已经做了一个莫比乌斯反演的题了,而题所要求得是GCD(x,y) = k的数量,而现在我们所要求得是GCD(x,y) = 质数的数量,和之前一样我们令 f(n)=∑[gcd(i,j)=n],g(n)=∑d|nf(d) ,那么我们可以得到 f(n)=∑n|dμ(dn)g(d)=∑n|dμ(dn)[xd][yd] ,由于我们是计算gcd(i,j) = 质数的数量,最简单的方式就是枚举质数计算总和,但是可能会超时,注意,对于同一个数d可能会重复计算几次,那么我们可以提前处理出来他被计算的系数,求一个前缀和。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
const int Max = 1e7+100;
int mu[Max];
int prime[Max],cnt;
int sum[Max];
bool vis[Max];
// 提前处理
void GetMobius(){
memset(vis,false,sizeof(vis));
memset(sum,0,sizeof(sum));
cnt = 0;
mu[1] = 1;
sum[0] = 0;
for(int i = 2;i < Max ; i++){
if(!vis[i]) {
prime[cnt++] = i;
mu[i] = -1;
}
for(int j = 0 ; j < cnt && i*prime[j] < Max ;j++){
vis[i*prime[j]] = true;
if(i%prime[j]) mu[i*prime[j]] = -mu[i];
else {
mu[i*prime[j]] = 0;
break;
}
}
}
for(int i = 0;i<cnt ;i++) {
for(int j = prime[i] ; j < Max ; j+=prime[i]) {
sum[j] += mu[j/prime[i]];
}
}
for(int i = 1;i<Max ;i++) {
sum[i] += sum[i-1];
}
}
LL Cal(LL n,LL m) {
int end; LL Sum = 0;
int S = min(n,m);
for(int i = 1 ;i <= S ; i= end+1) {
end = min(n/(n/i),m/(m/i));
Sum+=((sum[end]-sum[i-1])*(n/i)*(m/i));
}
return Sum;
}
int main() {
int T;
int n,m;
LL Sum ;
GetMobius();
scanf("%d",&T);
while(T--) {
scanf("%d %d",&n,&m);
Sum = 0;
Sum += Cal(n,m);
printf("%lld\n",Sum);
}
return 0;
}