bzoj 4176 Lucas的数论 莫比乌斯反演

ni=1nj=1d(i,j)=ni=1nj=1n2k=1[k|ij]
=ni=1nj=1n2k=1[kgcd(i,k)|j]=ni=1n2k=1ngcd(i,k)k
=nd=1ndi=1n2dk=1nk[gcd(i,k)=1]
=nd=1ndi=1nk=1nk[gcd(i,k)=1]
=nd=1ndi=1nk=1nkt|i,t|kμ(t)
=nt=1μ(t)nd=1ndti=1ntk=1nkt
=nt=1μ(t)nd=1ndtntk=1nkt
=nt=1μ(t)ntd=1ndtntk=1nkt
=nt=1μ(t)(ntd=1ndt)2

O(n) 枚举 nt , 一段区间的mu的和可以用3944的方法求。
(ntd=1ndt)2 O(nt) 求。

复杂度 O(n34)

#include 
using namespace std;
#define ll long long
#define M 15000000
#define M1 15000010
#define mod 1000000007
bool ip[M1];
int mu[M1],prime[M1/10];
int cnt,n,ans;
map<int,int>ma;
void init()
{
    mu[1]=1;
    for(int i=2;i<=M;i++)
    {
        if(!ip[i])prime[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&i*prime[j]<=M;j++)
        {
            ip[i*prime[j]]=1;
            if(i%prime[j]==0)break;
            mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<=M;i++)mu[i]+=mu[i-1];
}
int f(int x)
{
    if(x<=M)return mu[x];
    if(ma.count(x))return ma[x];
    int ret=1;
    for(int i=2,last;i<=x;i=last+1)
    {
        last=x/(x/i);
        ret-=f(x/i)*(last-i+1);
    }
    return ma[x]=ret;
}
int cal(int x)
{
    int ret=0;
    for(int i=1,last;i<=x;i=last+1)
    {
        last=x/(x/i);
        ret=(ret+(ll)(x/i)*(last-i+1)%mod)%mod;
    }
    return ret;
}
int main()
{
    //freopen("tt.in","r",stdin);
    init();
    scanf("%d",&n);
    for(int i=1,last;i<=n;i=last+1)
    {
        last=n/(n/i);
        int t=cal(n/i);
        ans=(ans+(ll)(f(last)-f(i-1))*t%mod*t%mod)%mod;
    }
    printf("%d\n",(ans+mod)%mod);
    return 0;
}

你可能感兴趣的:(莫比乌斯反演)