【LG2257】YY的GCD
题面
题解
题目大意:
给定(n,m)求(sum_{i=1}^{n}sum_{j=1}^{m}[gcd(i,j)为质数])。
我们设(f(x)=[x为质数]),需要找到一个(g)使得(f=1*g),那么(g=mu*f)
[g(x)=sum_{d|x}mu(frac{x}{d})*f(d)=sum_{p|x}mu(frac{x}{p})
]
这样的话,我们要求的就是
[sum_{i=1}^{n}sum_{j=1}^{m}sum_{d|i,d|j}g(d)\
=sum_{d=1}^{min(n,m)}g(d)sum_{i=1}^{n}sum_{j=1}^{m}[d|i][d|j]\
=sum_{d=1}^{min(n,m)}g(d)lfloorfrac{n}{d}
floorlfloorfrac{m}{d}
floor
]
可以用数论分块求出
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
return w * data;
}
typedef long long ll;
const int MAX_N = 1e7 + 5;
const int MAX = 1e7;
bool is_prime[MAX_N];
int prime[MAX_N], num, mu[MAX_N], s[MAX_N], f[MAX_N];
void sieve() {
for (int i = 1; i <= MAX; i++) is_prime[i] = 1;
is_prime[1] = 0, mu[1] = 1;
for (int i = 2; i <= MAX; i++) {
if (is_prime[i]) prime[++num] = i, mu[i] = -1;
for (int j = 1; j <= num && i * prime[j] <= MAX; j++) {
is_prime[i * prime[j]] = 0;
if (i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
}
for (int i = 1; i <= num; i++)
for (int j = 1; prime[i] * j <= MAX; j++)
f[j * prime[i]] += mu[j];
for (int i = 1; i <= MAX; i++) s[i] = s[i - 1] + f[i];
}
ll solve(int a, int b) {
ll ans = 0;
if (a > b) swap(a, b);
for (int l = 1, r = 0; l <= a; l = r + 1) {
r = min(a / (a / l), b / (b / l));
ans += 1ll * (s[r] - s[l - 1]) * (a / l) * (b / l);
}
return ans;
}
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
sieve();
int T = gi(), N, M;
while (T--) {
N = gi(), M = gi();
printf("%lld
", solve(N, M));
}
return 0;
}