杜教筛
有一数论函数 \(f\),求,
\[S(n) = \sum\limits_{i=1}^{n}f(i)
\]
构造两个积性函数 \(h\) 和 \(g\) 满足 \(h = f * g\)
\[\sum\limits_{i=1}^n f*g
\]
有,
\[\begin{align*}
\sum\limits_{i=1}^n f*g
& = \sum\limits_{i=1}^n\sum\limits_{d|i}g(d)f(\frac{i}{d}) \\
& = \sum\limits_{d=1}^n g(d) \sum\limits_{i=1}^{\frac{n}{d}}f(i) \\
& = g(1)S(n) + \sum\limits_{d=2}^n g(d)S(\lfloor\frac{n}{d}\rfloor)
\end{align*}
\]
接着,我们需要预处理 \(S(n) \leq 10^6\) 的前缀和,以方便计算。
在外部,使用记忆化搜索及整除分块,以保证时间复杂度是 \(O(n^\frac{2}{3})\)。
在内部,使用递归以快速求解。
以计算 \(\mu\) 和 \(\varphi\) 为例,我们有如下代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6+10;
int phi[N], mu[N], suphi[N], sumu[N], ans1, ans2;
bool notPrime[N];
vector<int>prime;
map<int, int>sudphi, sudmu;
int djsmu(int n){
if(sudmu.count(n)) return sudmu[n];
if(n <= 1e6) return sumu[n];
int ans = 1;
for(int l=2, r=0;l<=n;l=r+1){
r = (n/(n/l));
ans -= djsmu(n/l) * (r-l+1);
}
return sudmu[n] = ans;
}
int djsphi(int n){
if(sudphi.count(n)) return sudphi[n];
if(n <= 1e6) return suphi[n];
int ans = (n*(n+1))/2;
for(int l=2, r=0;l<=n;l=r+1){
r = (n/(n/l));
ans -= djsphi(n/l) * (r-l+1);
}
return sudphi[n] = ans;
}
void euler(int n){
phi[1] = 1, mu[1] = 1;
for(int i=2;i<=n;i++){
if(!notPrime[i]){
phi[i] = i-1;
mu[i] = -1;
prime.push_back(i);
}
for(auto p : prime){
if(i*p > n) break;
notPrime[i*p] = 1;
if(i%p==0){
phi[i*p] = p * phi[i];
mu[i*p] = 0;
break;
}
phi[i*p] = (p-1) * phi[i];
mu[i*p] = -mu[i];
}
}
for(int i=1;i<=n;i++){
suphi[i] = suphi[i-1] + phi[i];
sumu[i] = sumu[i-1] + mu[i];
}
}
signed main(){
euler(1e6);
int T;cin>>T;
while(T--){
int x;cin>>x;
cout<<djsphi(x)<<' '<<djsmu(x)<<'\n';
}
}

浙公网安备 33010602011771号