AtCoder ABC020D LCM Rush
远古 ABC 的题。
题意
给定 \(N,K\),求 \(\sum\limits_{i=1}^N \operatorname{lcm}(i,K)\),\(1 \le N,K \le 10^9\)。
思路
考虑推式子。
\[ans = \sum\limits_{i=1}^N \dfrac{iK}{\gcd(i,K)}
\]
考虑枚举因数,得
\[ans = \sum\limits_{d|K} \sum\limits_{i=1}^{N} [\gcd(i,K)=d] \cdot \dfrac{iK}{d}
\]
\[ans = K \sum\limits_{d|K}\sum\limits_{i=1}^{\left\lfloor\frac{N}{d}\right\rfloor} [\gcd(i,\dfrac{K}{d})=1] \cdot i
\]
令
\[\operatorname{calc}(n,m) = \sum\limits_{i=1}^n [\gcd(i,\dfrac{K}{m})=1] \cdot i
\]
则
\[ans = K \sum\limits_{d|K} \operatorname{calc}(\left\lfloor\frac{N}{d}\right\rfloor,d)
\]
考虑化简 \(\operatorname{calc}(n,m)\)。
\[\operatorname{calc}(t,d) = \sum\limits_{i=1}^t i \cdot \sum\limits_{p|i,p|\frac{K}{d}} \mu(p)
\]
\[\operatorname{calc}(t,d) = \sum\limits_{p | \frac{K}{d}} \mu(p) \sum\limits_{i=1}^t [p|i] \cdot i
\]
\[\operatorname{calc}(n,m) = \sum\limits_{p | \frac{K}{d}} p \cdot \mu(p) \sum\limits_{i=1}^{\frac{t}{p}} i
\]
到这一步 \(\operatorname{calc}(n,m)\) 就可以 \(O(\sqrt{n})\) 计算了。
由于值域为 \(10^9\),\(\mu\) 显然不能直接预处理。可以预处理出 \(x \in [1,10^7]\) 的 \(\mu(x)\),当求 \(\mu(x)\) 时,若 \(x \le 10^7\) 则直接返回预处理的值,否则 \(O(\sqrt{x})\) 求出 \(\mu(x)\)。
时间复杂度 \(O(能过)\)。
代码
code
/*
p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy
*/
#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
const int maxn = 10000100;
const int N = 10000000;
const ll mod = 1000000007;
const ll inv2 = 500000004;
ll n, K, pr[maxn], tot, mu[maxn];
bool vis[maxn];
map<int, int> mp;
void init() {
mu[1] = 1;
for (int i = 2; i <= N; ++i) {
if (!vis[i]) {
pr[++tot] = i;
mu[i] = -1;
}
for (int j = 1; j <= tot && i * pr[j] <= N; ++j) {
vis[i * pr[j]] = 1;
if (i % pr[j] == 0) {
mu[i * pr[j]] = 0;
break;
}
mu[i * pr[j]] = -mu[i];
}
}
}
int getmu(int x) {
if (x <= N) {
return mu[x];
}
if (mp.find(x) != mp.end()) {
return mp[x];
}
int ans = 1, t = x;
for (int i = 2; i * i <= x; ++i) {
if (x % i) {
continue;
}
int cnt = 0;
while (x % i == 0) {
x /= i;
++cnt;
}
if (cnt > 1) {
return mp[t] = 0;
}
ans = -ans;
}
if (x > 1) {
ans = -ans;
}
return mp[t] = ans;
}
ll calc(int n, int m) {
ll ans = 0, t = K / m;
for (int i = 1; i * i <= t; ++i) {
if (t % i) {
continue;
}
ans = (ans + ((1LL * i * getmu(i)) % mod + mod) % mod * (n / i) % mod * (n / i + 1) % mod * inv2 % mod) % mod;
if (i * i != t) {
int p = t / i;
ans = (ans + ((1LL * p * getmu(p)) % mod + mod) % mod * (n / p) % mod * (n / p + 1) % mod * inv2 % mod) % mod;
}
}
// printf("%d %d %lld\n", n, m, ans);
return ans;
}
void solve() {
scanf("%lld%lld", &n, &K);
ll ans = 0;
for (ll i = 1; i * i <= K; ++i) {
if (K % i) {
continue;
}
ans = (ans + calc(n / i, i)) % mod;
if (i * i != K) {
ans = (ans + calc(n / (K / i), K / i)) % mod;
}
}
ans = ans * K % mod;
printf("%lld\n", ans);
}
int main() {
init();
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}

浙公网安备 33010602011771号