题解 SP5971 【LCMSUM - LCM Sum】
SP5971 LCMSUM - LCM Sum
题意
思路
来一发不需要
根据
把
枚举
将
由
显然
改变顺序,先枚举
易知
令
令
枚举
令
(提示:下面的几个情况和欧拉筛一样)
-
n=1$,$f(n)=\mu(1)\times 1=1 -
n \in \mathbb{P}$,则 $f(n)=\mu(1)\times1+\mu(n)\times n=1-n - 否则,设
n=ij ,其中j 为n 的最小质因子- 若
i \operatorname{mod}j=0 ,则f(ij)=f(i) ,因为有j 之后,产生的所有新的质因子d ,都有\mu(d)=0 - 否则,
f(ij)=f(i)f(j) ,因为i 的每一个质因子t 乘j 之后都有\mu(tj)=-\mu(d) ,所以f(ij)=f(i)-jf(i)=(1-j)f(i)=f(i)f(j)
- 若
这时候我们已经能做到
#include <iostream>
const int MAXN = 1000000, lnMAXN = 12;
int Prime[MAXN/lnMAXN + 5], size; //Prime[i]为第i个质数
long long f[MAXN + 5], ans[MAXN + 5]; //开long long
bool not_prime[MAXN + 5]; //not_prime[i]=true 表示i为合数,否则为质数
inline long long S(int n)
{ return 1LL*n*(n + 1) >> 1; } //高斯求和公式,别忘了long long
void sieve(int n) {
f[1] = 1;
not_prime[1] = true;
//筛f
for(int i = 1; i <= n; ++i) {
if(not_prime[i] == false) { //i为质数
f[i] = 1 - i; //第1种情况
Prime[size++] = i; //加入质数表
}
for(int j = 0; j < size && i*Prime[j] <= n; ++j) {
not_prime[i*Prime[j]] = true;
if(i%Prime[j] == 0) {
f[i*Prime[j]] = f[i]; //第2种情况
break;
}
f[i*Prime[j]] = f[i]*f[Prime[j]]; //第3种情况
}
}
//筛ans
for(int i = 1; i <= n; ++i)
for(int j = 1; i*j <= n; ++j)
ans[i*j] += S(i)*f[j];
}
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(0), std::cout.tie(0);
sieve(MAXN);
int t, n;
std::cin >> t;
while(t--) {
std::cin >> n;
std::cout << 1LL*n*ans[n] << "\n";
}
return 0;
}
最后,对筛
这个过程的时间复杂度事实上为
那么我们将