题目描述
神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
输入输出格式
输入格式:
第一行一个整数T 表述数据组数
接下来T行,每行两个正整数,表示N, M
输出格式:
T行,每行一个整数表示第i组数据的结果
输入输出样例
输入样例#1: 复制
2
10 10
100 100
输出样例#1: 复制
30
2791
说明
T = 10000
N, M <= 10000000
题意:略。
分析:莫比乌斯反演套路。
设
f[n]=gcd==x的个数
F[n]=gcd==x与x的倍数的个数
接下来推公式。
令t=d/p
令T=tp
前面部分分块求,后面部分前缀和处理。
#include<bits/stdc++.h>
using namespace std;
long long mu[10000004];
long long prim[10000004];
bool vis[10000004];
int cnt = 0;
long long g[10000004];
long long pre[10000004];
void init() {
memset(prim, 0, sizeof(prim));
memset(mu, 0, sizeof(mu));
memset(vis, 0, sizeof(vis));
mu[1] = 1;
for (int i = 2; i < 10000004; ++i) {
if (!vis[i]) {
prim[cnt++] = i;
mu[i] = -1;
}
for (int j = 0; j < cnt && i * prim[j] < 10000004; ++j) {
vis[i * prim[j]] = 1;
if (i % prim[j] == 0)break;
else mu[i * prim[j]] = -mu[i];
}
}
for (int i = 0; i < cnt; ++i) {
for (int j = 1; j * prim[i] < 10000004; ++j) {
g[j * prim[i]] += mu[j];
}
}
for (int i = 1; i < 10000004; ++i) {
pre[i] = pre[i - 1] + g[i];
}
}
int main() {
init();
int T;
scanf("%d", &T);
while (T--) {
int n, m;
scanf("%d%d", &n, &m);
long long ans = 0;
int l, r;
if (n > m)swap(n, m);
for (l = 1; l <= n; l = r + 1) {
r = min(n / (n / l), m / (m / l));
ans += (long long) (n / l) * (m / l) * (pre[r] - pre[l - 1]);
}
printf("%lld\n", ans);
}
}