根据狄利克雷卷积的性质,可以在低于线性时间复杂度的情况下,求积性函数前缀和
#### 公式
$$
求\sum_{i=1}^{n}\mu(i)
$$
因为\(\mu*I=\epsilon\)
所以设\(h=\mu*I,S_n=\sum_{i=1}^n\mu(i)\)
\[\sum_{i=1}^{n}h(i)\]
\[=\sum_{i=1}^{n}\sum_{d|i}\mu(\lfloor\frac{i}{d}\rfloor)\times I(d)
\]
\]
\[=\sum_{i=1}^nI(i)\sum_{j=1}^{\lfloor \frac{n}{i}\rfloor}\mu(j)
\]
\]
\[=\sum_{i=1}^nI(i)\times S(\lfloor\frac{n}{i}\rfloor)
\]
\]
\[=I(1)\times S(n)+\sum_{i=2}^nI(i)\times S(\lfloor\frac{n}{i}\rfloor)\]
\[I(1)\times S(n)=\sum_{i=1}^{n}h(i)-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)
\]
\]
\[S(n)=1-\sum_{i=2}^n{S(\lfloor\frac{n}{i}\rfloor)}
\]
\]
\[求\sum_{i=1}^n\phi(i)
\]
\]
因为\(\phi*I=id\)
所以设\(h=\phi*I,S_n=\sum_{i=1}^n\phi_i\)
\[\sum_{i=1}^nh(i)$$$$=\sum_{i=1}^n\sum_{d|i}\phi(\lfloor\frac{i}{d}\rfloor)\times I(d)$$$$=\sum_{i=1}^nI(i)\times \sum_{d|i}\phi(\lfloor\frac{i}{d}\rfloor)$$$$=\sum_{i=1}^nI(i)\times \sum_{t=1}^{\lfloor\frac{n}{i}\rfloor}\phi(t)$$\]
=\sum_{i=1}^nI(i)\times S(\lfloor\frac{n}{i}\rfloor)$$$$
=I(1)\times S(n)+\sum_{i=2}^n I(i)\times S(\lfloor\frac{n}{i}\rfloor)
\[\]
S(n)=\sum_{i=1}nh(i)-\sum_{i=2}n I(i)\times S(\lfloor\frac{n}{i}\rfloor)
\[\]
S(n)=\frac{(n+1)\times n}{2}-\sum_{i=2}^n I(i)\times S(\lfloor\frac{n}{i}\rfloor)
\[#### 注意事项
- 尽量减少常数
- 开头线性筛预处理的时候尽量开到$n^{\frac{2}{3}}$或更大
- long long和int要区别
- 枚举2 TO N 可以整除分块
#### 代码
```cpp
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
const int MAXN = 5000000;
unordered_map<int,long long> Sumphi;
unordered_map<int,long long> Summu;
int iprime[MAXN+5],cnt;
long long mu[MAXN+5],phi[MAXN+5];
bool isprime[MAXN+5];
void prime(int n){
isprime[1]=true;
mu[1]=1;
phi[1]=1;
for(int i=2;i<=n;i++){
if(!isprime[i])
iprime[++cnt]=i,phi[i]=i-1,mu[i]=-1;
for(int j=1;j<=cnt&&iprime[j]*i<=n;j++){
isprime[iprime[j]*i]=true;
mu[iprime[j]*i]=-mu[i];
phi[iprime[j]*i]=phi[i]*(iprime[j]-1);
if(i%iprime[j]==0){
mu[iprime[j]*i]=0;
phi[iprime[j]*i]=phi[i]*(iprime[j]);
break;
}
}
}
for(int i=1;i<=n;i++){
mu[i]+=mu[i-1];
phi[i]+=phi[i-1];
}
}
long long djsmu(int n){//first mu second phi
if(n<=MAXN)
return mu[n];
if(Summu.count(n))
return Summu[n];
int mid1=0;
for(int i=2,j;i<=n;i=j+1){
j=min(n/(n/i),n);
mid1+=(j-i+1)*djsmu(n/i);
}
Summu[n]=1-mid1;
return Summu[n];
}
long long djsphi(int n){//first mu second phi
if(n<=MAXN)
return phi[n];
if(Sumphi.count(n))
return Sumphi[n];
long long mid1=0;
for(int i=2,j;i<=n;i=j+1){
j=min(n/(n/i),n);
mid1+=(j-i+1)*djsphi(n/i);
}
Sumphi[n]=1LL*(n+1)*n/2-mid1;
return Sumphi[n];
}
int main(){
prime(MAXN);
int T,n;
scanf("%d",&T);
for(int i=1;i<=T;i++){
scanf("%d",&n);
printf("%lld %d\n",djsphi(n),djsmu(n));
}
return 0;
}
```\]
- 尽量减少常数
- 开头线性筛预处理的时候尽量开到$n^{\frac{2}{3}}$或更大
- long long和int要区别
- 枚举2 TO N 可以整除分块
#### 代码
```cpp
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
const int MAXN = 5000000;
unordered_map<int,long long> Sumphi;
unordered_map<int,long long> Summu;
int iprime[MAXN+5],cnt;
long long mu[MAXN+5],phi[MAXN+5];
bool isprime[MAXN+5];
void prime(int n){
isprime[1]=true;
mu[1]=1;
phi[1]=1;
for(int i=2;i<=n;i++){
if(!isprime[i])
iprime[++cnt]=i,phi[i]=i-1,mu[i]=-1;
for(int j=1;j<=cnt&&iprime[j]*i<=n;j++){
isprime[iprime[j]*i]=true;
mu[iprime[j]*i]=-mu[i];
phi[iprime[j]*i]=phi[i]*(iprime[j]-1);
if(i%iprime[j]==0){
mu[iprime[j]*i]=0;
phi[iprime[j]*i]=phi[i]*(iprime[j]);
break;
}
}
}
for(int i=1;i<=n;i++){
mu[i]+=mu[i-1];
phi[i]+=phi[i-1];
}
}
long long djsmu(int n){//first mu second phi
if(n<=MAXN)
return mu[n];
if(Summu.count(n))
return Summu[n];
int mid1=0;
for(int i=2,j;i<=n;i=j+1){
j=min(n/(n/i),n);
mid1+=(j-i+1)*djsmu(n/i);
}
Summu[n]=1-mid1;
return Summu[n];
}
long long djsphi(int n){//first mu second phi
if(n<=MAXN)
return phi[n];
if(Sumphi.count(n))
return Sumphi[n];
long long mid1=0;
for(int i=2,j;i<=n;i=j+1){
j=min(n/(n/i),n);
mid1+=(j-i+1)*djsphi(n/i);
}
Sumphi[n]=1LL*(n+1)*n/2-mid1;
return Sumphi[n];
}
int main(){
prime(MAXN);
int T,n;
scanf("%d",&T);
for(int i=1;i<=T;i++){
scanf("%d",&n);
printf("%lld %d\n",djsphi(n),djsmu(n));
}
return 0;
}
```\]