luogu

链接:https://www.luogu.org/problemnew/show/P2257
思路:给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对。
我们设

得出:

莫比乌斯反演得到:

$我们更改枚举项,枚举lfloorfrac{d}{p}rfloor$:

我们将dp换成T:

推到这里就可以解决了,由于是多组数据,我们需要预处理。后面的对$mu$求和我们可以事先预处理出来,剩下的就是整除分块求答案即可。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

using namespace std;

const int maxn = 1e7 + 233;
int mu[maxn];
vector<int> prime;
bool vis[maxn];
typedef long long ll;
ll sum[maxn], g[maxn];

void (){
mu[1] = 1;
for(int i = 2; i < maxn; i++){
if(!vis[i]) {
mu[i] = -1;
prime.emplace_back(i);
}
for(int j = 0; j < prime.size() && i * prime[j] < maxn; j++){
vis[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
}
for(int j = 0; j < prime.size(); j++){
for(int i = 1; i * prime[j] < maxn; i++) g[i * prime[j]] += mu[i];
}
for(int i = 1; i < maxn; i++) sum[i] = sum[i - 1] + g[i];
}

int T, n, m;

int main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> T;
init();
while(T--){
cin >> n >> m;
if(n > m) swap(n, m);
ll res = 0;
for(int l = 1, r; l <= n; l = r + 1){
r = min(n / (n / l), m / (m / l));
res += 1ll * (n / l) * (m / l) * (sum[r] - sum[l - 1]);
}
cout << res << 'n';
}
return 0;
}