题意
求 ∑ni=1∑mj=1[gcd(i,j)isprime] ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) i s p r i m e ]
题解
不妨设 n≤m n ≤ m ,推一下式子
于是枚举 p p ,线性筛求出莫比乌斯函数的前缀和,然后整除分块做
#include <cstring>
#include <cstdio>
typedef long long LL;
const int MAXN = 1e7 + 10;
bool tag[MAXN];
int pr[MAXN], tot, n, m;
int mu[MAXN], mus[MAXN];
void init(int n) {
memset(tag, 1, sizeof tag);
tag[1] = false;
mu[1] = mus[1] = 1;
for(int i = 2; i <= n; i ++) {
if(tag[i]) {
pr[++ tot] = i;
mu[i] = -1;
}
for(int j = 1; j <= tot && pr[j] * (LL)i <= n; j ++) {
tag[i * pr[j]] = false;
if(i % pr[j] == 0) {
mu[i * pr[j]] = 0;
break ;
}
mu[i * pr[j]] = - mu[i];
}
mus[i] = mus[i - 1] + mu[i];
}
}
LL calc(int r1, int r2) {
LL ans = 0;
int r = (r1 < r2 ? r1 : r2);
for(int i = 1, j; i <= r; i = j + 1) {
j = r1 / (r1 / i);
if(j > r2 / (r2 / i)) j = r2 / (r2 / i);
ans += (mus[j] - mus[i-1]) * 1ll * (r1 / i) * (r2 / i);
}
return ans;
}
int main() {
init(1e7);
int T;
scanf("%d", &T);
for(; T --; ) {
scanf("%d%d", &n, &m);
LL ans = 0;
int x = (n < m ? n : m);
for(int i = 1; i <= tot && pr[i] <= x; i ++)
ans += calc(n / pr[i], m / pr[i]);
printf("%lld\n", ans);
}
return 0;
}
于是:喜闻乐见
考虑优化:
枚举 T=pd T = p d :
于是我们可以预处理后面的 μ μ ,询问的时间复杂度从玄学的 O(?) O ( ? ) 优化到 O(n−−√+m−−√) O ( n + m )
#include <cstring>
#include <cstdio>
typedef long long LL;
const int MAXN = 1e7 + 10;
bool tag[MAXN];
int pr[MAXN], tot, n, m;
int mu[MAXN];
LL sum[MAXN];
void init(int n) {
memset(tag, 1, sizeof tag);
tag[1] = false;
mu[1] = 1;
for(int i = 2; i <= n; i ++) {
if(tag[i]) {
pr[++ tot] = i;
mu[i] = -1;
}
for(int j = 1; j <= tot && pr[j] * (LL)i <= n; j ++) {
tag[i * pr[j]] = false;
if(i % pr[j] == 0) {
mu[i * pr[j]] = 0;
break ;
}
mu[i * pr[j]] = - mu[i];
}
}
for(int i = 1; i <= tot; i ++)
for(int j = 1; j * 1ll * pr[i] <= n; j ++)
sum[j * pr[i]] += mu[j];
for(int i = 1; i <= n; i ++)
sum[i] += sum[i - 1];
}
LL calc(int r1, int r2) {
LL ans = 0;
int r = (r1 < r2 ? r1 : r2);
for(int i = 1, j; i <= r; i = j + 1) {
j = r1 / (r1 / i);
if(j > r2 / (r2 / i)) j = r2 / (r2 / i);
ans += (sum[j] - sum[i-1]) * 1ll * (r1 / i) * (r2 / i);
}
return ans;
}
int main() {
init(1e7);
int T; scanf("%d", &T);
for(; T --; ) {
scanf("%d%d", &n, &m);
if(n > m) n ^= m ^= n ^= m;
printf("%lld\n", calc(n, m));
}
return 0;
}