一般求法:
求
找出兩個積性函數和,滿足,(*表示卷積)
然後有
記
右邊提取第一項,把剩餘的移到左邊等式變爲:
通常和很容易快速得到,所以只要解決這部分就可以得到
這部分可以使用分塊快速得到
一般是先對可打表的範圍預處理,然後求解的時候如果n較小,直接輸出答案即可;n較大時採用遞歸求解的方式來解決。需要保存那些不在打表範圍的結果,也就是記憶化。
模板題中:
求
容易想到,其中
求
容易想到,其中
後面照着過程一步一步下來很容易可以解出
常用數論函數:
函數 | |
---|---|
因數個數 | |
因數和 | |
幺元函數 | |
恆等函數 | |
歐拉函數 | |
莫比烏斯函數 | |
單位函數 | |
冪函數 |
參考:
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int N=5e6+5;
const int M=5e6;
int mu[N];
ll phi[N];
bool vis[N];
int prime[N],tot;
void work_pre(int maxn)
{
phi[1]=mu[1]=1;
for(int i=2;i<=maxn;i++)
{
if(!vis[i])
{
prime[++tot]=i;
mu[i]=-1;phi[i]=i-1;
}
for(int j=1;j<=tot&&prime[j]*i<=maxn;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else mu[i*prime[j]]=-mu[i],phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for(int i=1;i<=maxn;i++){
phi[i]+=phi[i-1];
mu[i]+=mu[i-1];
}
}
unordered_map<int,int>mp1;
unordered_map<int,ll>mp2;
int djs_mu(int n){
if(n<=M){
return mu[n];
}
if(mp1[n]){
return mp1[n];
}
int ret=1;
for(int l=2,r;n>=l;l=r+1){
r=n/(n/l);
ret-=(r-l+1)*djs_mu(n/l);
}
return mp1[n]=ret;
}
ll djs_phi(int n){
if(n<=M){
return phi[n];
}
if(mp2[n]){
return mp2[n];
}
ll ret=1ll*n*(n+1)/2;
for(int l=2,r;n>=l;l=r+1){
r=n/(n/l);
ret-=1ll*(r-l+1)*djs_phi(n/l);
}
return mp2[n]=ret;
}
int main(){
work_pre(M);
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++){
int n;
scanf("%d",&n);
printf("%lld %d\n",djs_phi(n),djs_mu(n));
}
return 0;
}