杜教篩模板題

鏈接

一般求法:

i=1nf(x)\sum_{i=1}^{n}{f(x)}

找出兩個積性函數h(x)h(x)g(x)g(x),滿足g(x)=h(x)f(x)g(x)=h(x)*f(x),(*表示卷積)

然後有i=1ng(x)=i=1ndih(d)f(nd)\sum_{i=1}^{n}g(x)=\sum_{i=1}^{n}\sum_{d|i}h(d)\cdot f(\frac{n}{d})

i=1ng(x)=d=1nh(d)j=1ndf(j)\sum_{i=1}^{n}g(x)=\sum_{d=1}^{n}h(d)\cdot\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}f({j})

s(x)=i=1xf(x)s(x)=\sum_{i=1}^{x}f(x)

i=1ng(x)=d=1nh(d)s(nd))\sum_{i=1}^{n}g(x)=\sum_{d=1}^{n}h(d)\cdot s(\lfloor\frac{n}{d}\rfloor))

右邊提取第一項h(1)s(1)h(1)*s(1),把剩餘的移到左邊等式變爲:

h(1)s(n)=i=1ng(x)d=2nh(d)s(nd))h(1)*s(n) =\sum_{i=1}^{n}g(x) -\sum_{d=2}^{n}h(d)\cdot s(\lfloor\frac{n}{d}\rfloor))

通常i=1ng(x)\sum_{i=1}^{n}g(x)h(1)h(1)很容易快速得到,所以只要解決d=2nh(d)s(nd))\sum_{d=2}^{n}h(d)\cdot s(\lfloor\frac{n}{d}\rfloor))這部分就可以得到s(n)s(n)
這部分可以使用分塊快速得到

一般是先對可打表的範圍預處理,然後求解的時候如果n較小,直接輸出答案即可;n較大時採用遞歸求解的方式來解決。需要保存那些不在打表範圍的結果,也就是記憶化。

模板題中:
i=1nϕ(i)\sum_{i=1}^{n}\phi(i)
容易想到ϕI=id\phi*I=id,其中I(x)=1,id(x)=xI(x)=1,id(x)=x

i=1nμ(i)\sum_{i=1}^{n}\mu(i)
容易想到μI=e\mu*I=e,其中I(x)=1,e(x)=(x=1?1:0)I(x)=1,e(x)=(x=1?1:0)

後面照着過程一步一步下來很容易可以解出


常用數論函數:

函數
d(n)=dn1d(n)=\sum_{d\|n}1 因數個數
σ(n)=dnd\sigma(n)=\sum_{d\|n}d 因數和
e(n)=n==1?1:0e(n)=n==1?1:0 幺元函數
I(n)=1I(n)=1 恆等函數
ϕ(n)\phi(n) 歐拉函數
μ(n)\mu(n) 莫比烏斯函數
id(n)=nid(n)=n 單位函數
idk(n)=nkidk(n)=n^{k} 冪函數

μ1=ϵ\mu * 1=\epsilon
ϕ1=Id\phi * 1=Id
ϕ=Idμ\phi = Id * \mu
d=11d=1∗1
1=μd1 = \mu * d

參考:

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章