有一个M * N的表格,行与列分别是1 - M和1 - N,格子中间写着行与列的最大公约数Gcd(i, j)(1 <= i <= M, 1 <= j <= N)。
例如:M = 5, n = 4。
1 2 3 4 5
1 1 1 1 1 1
2 1 2 1 2 1
3 1 1 3 1 1
4 1 2 1 4 1
给出M和N,求这张表中有多少个质数。
收起
输入
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 1000) 第2 - T + 1行:每行2个数M,N,中间用空格分隔,表示表格的宽和高。(1 <= M, N <= 5 * 10^6)
输出
共T行,每行1个数,表示表格中质数的数量。
输入样例
2 10 10 100 100
输出样例
30 2791
题解:反演的公式记住就行,主要是把F(x) 和 f(x) 找到
要先把莫比乌斯函数求出来,把结果后部分预处理出个前缀和,然后前面通过枚举d分块来求,直接枚举会超时
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e6 + 10;
int prime[N], len;
bool isp[N];
int mu[N];
int sum[N], a[N];
void init() {
mu[1] = 1;
for(int i = 2; i < 5000000; i++) {
if(!isp[i]) {
prime[len++] = i;
mu[i] = -1;
}
for(int j = 0; j < len && (ll)i * prime[j] < 5000000; j++) {
isp[i * prime[j]] = 1;
if(i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
} else {
mu[i * prime[j]] = -mu[i];
}
}
}
for(int i = 0; i < len; i++)
for(int j = prime[i]; j < 5000000; j += prime[i])
a[j] += mu[j / prime[i]];
for(int i = 1; i <= 5000000; i++)
sum[i] = sum[i - 1] + a[i];
}
int main() {
init();
int T , CM, r;
int n, m;
ll ans;
scanf("%d", &T);
while(T--) {
scanf("%d %d", &n, &m);
ans = 0;
CM = min(n, m);
/*
for(int i = 1; i <= CM; i++)
ans += (ll)(n / i) * (m / i) * a[i];
*/
for(int i = 1; i <= CM; i = r + 1) {
r = min(n / (n / i), m / (m / i));
ans += (ll)(n / i) * (m / i) * (sum[r] - sum[i - 1]);
}
printf("%lld\n", ans);
}
return 0;
}