莫比乌斯反演模板

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
#include <bits/stdc++.h>

using namespace std;
const int mx = 1e5+5;
typedef long long ll;

bool vis[mx];
int sum[mx], prim[mx], mu[mx], cnt = 0;

void get_mu(){
mu[1] = 1;
for(int i = 2; i< mx; i++){
if(!vis[i]) {
prim[++cnt] = i;
mu[i] = -1;
}
for(int j = 1; j <= cnt && prim[j]*i < mx; j++) {
vis[prim[j]*i] = 1;
if(i % prim[j] == 0) break;
else mu[i*prim[j]] = -mu[i];
}
}
sum[0] = 0;
for (int i = 0; i < mx; i++) sum[i] = sum[i-1]+ mu[i];
}


int main() {
get_mu();
int n, m;
scanf("%d%d", &n, &m);

int len = min(n, m);
int last;

ll ans = 0;
/*利用n/i连续区间数值相同的性质进行分块计算,可把复杂度降为sqrt(n) */
for (int i = 1; i <= len; i=last+1) {
last = min(n/(n/i), m/(m/i));
ans += 1LL * (sum[last] - sum[i-1]) * (n/i) * (m/i);
}
printf("%lld\n", ans);

}