Simple Sum 题解
题目大意,给一个正整数 \(n\),求 \(\sum_{i=1}^n \frac{n}{gcd(i, n)}\) 的值。
显然题目的答案为 \(\sum_{d|n} d\varphi(d)\),定义为 \(f(n)\)。
现在,我们假设 \(n=k\times p^q\),其中 \(p\) 为 \(n\) 的最小质因子。
发现:
也就是:
进一步得出,对于互质的两个数 \(m,n\),\(f(m)\times f(n)=f(mn)\)。即 \(f\) 为积性函数。
下面我们开始玩板子线性筛推积性函数。
-
\(i\) 是质数,求 \(f(i)\)。
根据定义,有 \(f_i=1+\varphi(i)i=i(i-1)+1\)。
-
\(p\) 是 \(i\) 的最小质因数,求 \(f(ip)\)。
令 \(i=xp^k\),\(x\) 为正整数,\(k\) 为正整数且最大。所以有:\(f(ip)=f\left(i/p^k\times p^{k+1}\right)=f\left(i/p^k\right)\times f\left(p^{k+1}\right)\)。而因为
\[f\left(p^{k+1}\right)=\sum_{i=0}^{k+1}p^i\varphi(p^i)=\sum_{i=0}^{k}p^i\varphi(p^i)+p^{k+1}\varphi(p^{k+1})=f\left(p^k\right)+p^{k+1}\varphi(p^{k+1}) \]所以 \(f(ip)=f\left(i/p^k\times p^{k+1}\right)=f\left(i/p^k\right)\times \left(f\left(p^k\right)+p^{k+1}\varphi(p^{k+1})\right)\)。
-
\(p\) 是质数,与 \(i\) 互质,求 \(f(ip)\)。
\[f(ip)=\sum_{x\mid i}f(x)+f(xp)=\sum_{x\mid i}f(x)+f(p)\times f(x)=\sum_{x\mid i}f(x)\times (1+f(p)) \]
这时就会有聪明的脑板问了:主播主播,怎么知道对于 \(i\) 和与他唯一对应的 \(p\),他的 \(k\) 是多少(指第二种情况)?问得好。其实 \(g(i)\) 也可以线性筛递推。递推如下:
一道题,两次线性筛,求三个函数,也是没谁了。时间复杂度 \(O(n+t)\),跑的比 \(O(n+t\log n)\) 慢。
代码:
#include <bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
#define int ll
using ll = long long;
using pii = pair<int, int>;
const int N = 1e7 + 5;
int lp[N];
ll sum[N], f[N], phi[N];
int g[N];
vector<int> prime;
void init(void) {
phi[1] = 1;
g[1] = 1;
for (int i = 2; i <= 1e7; ++i) {
if (lp[i] == 0) {
lp[i] = i;
phi[i] = i - 1;
g[i] = 1;
prime.push_back(i);
}
for (auto x : prime) {
if (i * x > 1e7) break;
if (i % x == 0) {
phi[i * x] = phi[i] * x;
lp[i * x] = x;
g[i * x] = g[i];
break;
}
else {
phi[i * x] = phi[i] * (x - 1);
lp[i * x] = x;
g[i * x] = i;
}
}
}
f[1] = 1;
for (int i = 2; i <= 1e7; ++i) {
if (lp[i] == i)
f[i] = i * (i - 1) + 1;
for (auto x : prime) {
if (i * x > 1e7) break;
if (i % x == 0) {
f[i * x] = f[g[i]] * (f[i / g[i]] + phi[i / g[i] * x] * i / g[i] * x);
break;
}
else {
f[i * x] = f[i] * f[x];
}
}
}
}
signed main() {
FASTIO;
init();
int t; cin >> t;
while (t --) {
int n; cin >> n;
cout << f[n] << '\n';
}
return 0;
}

浙公网安备 33010602011771号