AtCoder ABC020D LCM Rush

洛谷传送门

AtCoder 传送门

远古 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;
}

posted @ 2022-07-12 19:38  zltzlt  阅读(70)  评论(0)    收藏  举报