1. 程式人生 > >[學習筆記]莫比烏斯反演

[學習筆記]莫比烏斯反演

1、\(Crash\)的數字表格

\(assume\ n<m\)

\(\sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)\)

\(\sum_{d=1}^{n}\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==d]\frac{ij}{d}\)

\(\sum_{d=1}^{n}d\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}[gcd(i,j)==1]ij\)

\(\sum_{d=1}^{n}d\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}\sum_{x|gcd(i,j)}\mu(x)ij\)

\(\sum_{d=1}^{n}d\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}\sum_{x|i,x|j}\mu(x)ij\)

\(\sum_{x=1}^{n}\sum_{d=1}^{n}d\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}\mu(x)ij[x|i,x|j]\)

\(assume\ i=ix,j=jx\)

\(\sum_{x=1}^{n}\mu(x)x^{2}\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{dx}}\sum_{j=1}^{\frac{m}{dx}}ij\)

\(g(x)=\sum_{i=1}^{\frac{n}{dx}}\sum_{j=1}^{\frac{n}{dx}}ij=[\frac{\frac{n}{dx}(\frac{n}{dx}+1)}{2}]^{2}\)

\(\sum_{d=1}^{n}d\sum_{x=1}^{n/d}\mu(x)x^{2}g(x)\)

用數論分塊優化\(O(n\sqrt{n})\)

記得開\(O_{2}\)

\(Code\ Below:\)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=10000000+10;
const int p=20101009;
ll n,m,prim[maxn],vis[maxn],mu[maxn],sum[maxn],cnt,ans;
ll a,b,d;

void getmu(ll n){
    mu[1]=1;
    register ll i,j;
    for(i=2;i<=n;i++){
        if(!vis[i]){prim[++cnt]=i;mu[i]=-1;}
        for(j=1;i*prim[j]<=n&&j<=cnt;j++){
            vis[i*prim[j]]=1;
            if(i%prim[j]==0) break;
            mu[i*prim[j]]=-mu[i];
        }
    }
    for(i=1;i<=n;i++) sum[i]=(sum[i-1]+mu[i]*i*i%p)%p;
}

ll g(ll x){
    return ((a/x)*(a/x+1)/2%p)*((b/x)*(b/x+1)/2%p)%p;
}

int main()
{
    scanf("%lld%lld",&n,&m);
    if(n>m) swap(n,m);
    getmu(n);
    register ll l,r,num;
    for(d=1;d<=n;d++){
        num=0;a=n/d;b=m/d;
        for(l=1;l<=a;l=r+1){
            r=min(a/(a/l),b/(b/l));
            num=(num+(sum[r]-sum[l-1])*g(l)%p)%p;
        }
        ans=(ans+d*num%p)%p;
    }
    printf("%lld\n",(ans+p)%p);
    return 0;
}

2、簡單的數學題

\(\sum_{i=1}^{n}\sum_{j=1}^{n}ijgcd(i,j)\)

\(\sum_{d=1}^{n}d\sum_{i=1}^{n}\sum_{j=1}^{n}[gcd(i,j)==d]ij\)

\(\sum_{d=1}^{n}d^{3}\sum_{i=1}^{n/d}\sum_{j=1}^{n/d}[gcd(i,j)==1]ij\)

\(\sum_{d=1}^{n}d^{3}\sum_{i=1}^{n/d}\sum_{j=1}^{n/d}\sum_{x|gcd(i,j)}\mu(x)ij\)

\(\sum_{d=1}^{n}d^{3}\sum_{i=1}^{n/d}\sum_{j=1}^{n/d}\sum_{x=1}^{n/d}\mu(x)[x|i,x|j]ij\)

\(assume\ i=ix,j=jx\)

\(\sum_{d=1}^{n}d^{3}\sum_{x=1}^{n/d}\mu(x)x^{2}\sum_{i=1}^{\frac{n}{dx}}\sum_{j=1}^{\frac{n}{dx}}ij\)

\(g(x)=\sum_{i=1}^{\frac{n}{dx}}\sum_{j=1}^{\frac{n}{dx}}ij=[\frac{\frac{n}{dx}(\frac{n}{dx}+1)}{2}]^{2}\)

\(\sum_{d=1}^{n}d^{3}\sum_{x=1}^{n/d}\mu(x)x^{2}g(x)\)

突然發現時間複雜度\(O(n\sqrt{n})\),解法是偽的

所以\(mobius\)卷積沒用了,要用\(phi\)卷積

\(\sum_{i=1}^{n}\sum_{j=1}^{n}ijgcd(i,j)\)

\(\sum_{i=1}^{n}\sum_{j=1}^{n}ij\sum_{k|i,k|j}\varphi(k)\)

\(\sum_{k=1}^{n}\varphi(k)\sum_{k|i}\sum_{k|j}ij\)

\(\sum_{k=1}^{n}\varphi(k)\sum_{i=1}^{n}\sum_{j=1}^{n}[k|i,k|j]ij\)

\(\sum_{k=1}^{n}\varphi(k)k^{2}\sum_{i=1}^{n/k}\sum_{j=1}^{n/k}ij\)

\(g(x)=(\sum_{i=1}^{x}i)^{2}=[\frac{x(x+1)}{2}]^{2}\)

\(\sum_{k=1}^{n}\varphi(k)k^{2}g(n/k)^{2}\)

#include <bits/stdc++.h>
#define ll long long
#define res register ll
using namespace std;
const int maxn=7500000+10;
ll p,n,prim[maxn],vis[maxn],phi[maxn],cnt,ans,inv2,inv6;
map<ll,ll> Phi;

ll fast_pow(ll a,ll b){
    ll ret=1;
    for(;b;b>>=1,a=a*a%p)
        ret=ret*(b&1?a:1)%p;
    return ret;
}

void getphi(ll n){
    phi[1]=1;
    res i,j;
    for(i=2;i<=n;i++){
        if(!vis[i]){prim[++cnt]=i;phi[i]=i-1;}
        for(j=1;i*prim[j]<=n&&j<=cnt;j++){
            vis[i*prim[j]]=1;
            if(i%prim[j]==0){
                phi[i*prim[j]]=phi[i]*prim[j]%p;
                break;
            }
            phi[i*prim[j]]=phi[i]*(prim[j]-1)%p;
        }
    }
    for(i=1;i<=n;i++) phi[i]=(i*i%p*phi[i]%p+phi[i-1])%p;
}

ll g(ll x){
    x%=p;
    return (x*(x+1)/2%p)*(x*(x+1)/2%p)%p;
}

ll f(ll x){
    x%=p;
    return x*(x+1)%p*(2*x+1)%p*inv6%p;
}


ll calc_phi(res n){
    if(n<=7500000) return phi[n];
    if(Phi[n]) return Phi[n];
    res ans=g(n);
    for(res l=2,r;l<=n;l=r+1){
        r=n/(n/l);
        ans=(ans-(f(r)-f(l-1)+p)%p*calc_phi(n/l)%p)%p;
    }
    return Phi[n]=(ans+p)%p;
}

int main()
{
    scanf("%lld%lld",&p,&n);
    getphi(7500000);
    inv2=fast_pow(2,p-2);
    inv6=fast_pow(6,p-2);
    for(res l=1,r;l<=n;l=r+1){
        r=n/(n/l);
        ans=(ans+(calc_phi(r)-calc_phi(l-1)+p)%p*g(n/l)%p)%p;
    }
    printf("%lld\n",(ans+p)%p);
    return 0;
}

3、於神之怒加強版

\(assume\ n<m\)

\(\sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)^{k}\)

\(\sum_{d=1}^{n}d^{k}\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==d]\)

\(\sum_{d=1}^{n}d^{k}\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}[gcd(i,j)==1]\)

\(\sum_{d=1}^{n}d^{k}\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}\sum_{x|gcd(i,j)}\mu(x)\)

\(\sum_{d=1}^{n}d^{k}\sum_{x=1}^{n}\mu(x)\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}[x|i,x|j]\)

\(\sum_{d=1}^{n}d^{k}\sum_{x=1}^{n/d}\mu(x)\lfloor\frac{n}{dx}\rfloor\lfloor\frac{m}{dx}\rfloor\)

\(\sum_{t=1}^{n}\lfloor\frac{n}{t}\rfloor\lfloor\frac{m}{t}\rfloor\sum_{d|t}d^{k}\mu(\frac{t}{d})\)

\(f(x)=\sum_{d|t}d^{k}\mu(\frac{t}{d})\)

\(\sum_{t=1}^{n}f(t)\lfloor\frac{n}{t}\rfloor\lfloor\frac{m}{t}\rfloor\)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5000000+10;
const int p=1e9+7;
ll n,m,k,prim[maxn],vis[maxn],f[maxn],cnt,ans;

ll fast_pow(ll a,ll b){
    ll ret=1;
    for(;b;b>>=1,a=a*a%p)
        ret=ret*(b&1?a:1)%p;
    return ret;
}

void sieve(ll n){
    f[1]=1;
    ll i,j;
    for(i=2;i<=n;i++){
        if(!vis[i]){prim[++cnt]=i;f[i]=fast_pow(i,k)-1;}
        for(j=1;i*prim[j]<=n&&j<=cnt;j++){
            vis[i*prim[j]]=1;
            if(i%prim[j]==0){
                f[i*prim[j]]=f[i]*(f[prim[j]]+1)%p;
                break;
            }
            f[i*prim[j]]=f[i]*f[prim[j]]%p;
        }
    }
    for(i=1;i<=n;i++) f[i]=(f[i]+f[i-1])%p;
}

int main()
{
    ll T,l,r;
    scanf("%lld%lld",&T,&k);
    sieve(5000000);
    while(T--){
        scanf("%lld%lld",&n,&m);
        if(n>m) swap(n,m);
        ans=0;
        for(l=1,r;l<=n;l=r+1){
            r=min(n/(n/l),m/(m/l));
            ans=(ans+(n/l)*(m/l)%p*(f[r]-f[l-1]+p)%p)%p;
        }
        printf("%lld\n",ans);
    }
    return 0;
}