BZOJ 3309: DZY Loves Math (莫比乌斯反演)
反演比较简单,可以化成
后面这一坨怎么推的具体见 FromATP的博客
不看题解我不会aaa…w(゚Д゚)w
CODE
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 10000000;
int prime[MAXN/10], cnt, e[MAXN+5], g[MAXN+5];
LL F[MAXN+5];
bool vis[MAXN+5];
inline void Pre_Work(int n) {
F[1] = e[1] = 0; g[1] = 1;
for(int i = 2; i <= n; ++i) {
if(!vis[i])
prime[++cnt] = i, F[i] = e[i] = 1, g[i] = i;
for(int j = 1; j <= cnt && i*prime[j] <= n; ++j) {
vis[i*prime[j]] = 1;
if(i % prime[j] == 0) {
g[i*prime[j]] = g[i] * prime[j];
e[i*prime[j]] = e[i] + 1;
int tmp = i / g[i];
if(tmp == 1) F[i*prime[j]] = 1;
else F[i*prime[j]] = (e[i*prime[j]] == e[tmp] ? -F[tmp] : 0);
break;
}
g[i*prime[j]] = prime[j];
e[i*prime[j]] = 1;
F[i*prime[j]] = (e[i] == 1 ? -F[i] : 0);
}
}
for(int i = 2; i <= n; ++i) F[i] += F[i-1];
}
inline LL solve(int n, int m) {
if(m < n) swap(n, m);
LL re = 0;
for(int i = 1, j; i <= n; i = j+1) {
j = min(n/(n/i), m/(m/i));
re += 1ll * (n/i) * (m/i) * (F[j] - F[i-1]);
}
return re;
}
int main() {
int n, m, T;
scanf("%d", &T);
Pre_Work(MAXN);
while(T--) {
scanf("%d%d", &n, &m);
printf("%lld\n", solve(n, m));
}
}