【51nod1222】【最小公倍数计数】【莫比乌斯反演】

题目大意

定义F(n)表示最小公倍数为n的二元组的数量。

即:如果存在两个数(二元组)X,Y(X <= Y),它们的最小公倍数为N,则F(n)的计数加1。

例如:F(6) = 5,因为[2,3] [1,6] [2,6] [3,6] [6,6]的最小公倍数等于6。

给出一个区间[a,b],求最小公倍数在这个区间的不同二元组的数量。

例如:a = 4,b = 6。符合条件的二元组包括:

[1,4] [2,4] [4,4] [1,5] [5,5] [2,3] [1,6] [2,6] [3,6] [6,6],共10组不同的组合。

解题思路

先不考虑偏序限制。

Ans=Nd=1N/dx=1N/dy=1[(dxy<=N)((x,y)==1)]

Ans=Ni=1mu[i]Nd=1N/dx=1N/dy=1[(dxy<=N)((x,y)==i)]

Ans=Ni=1mu[i]N/id=1N/d/ix=1N/d/iy=1[di2xy<=N]

观察可知i<=sqrt(N),发现d,x,y其实是等价的,我们可以强制他们满足偏序关系且互不相同,那d<=pow(N/i/i,1/3),x<=sqrt(N/i/i/d),y的取值范围可以直接算出来。

对于一对相同的,三个相同的可以类似算出。最后加上x==y的情况除以2就是答案。

code

#include
#include
#include
#include
#define LF double
#define LL long long
#define Min(a,b) ((a
#define Max(a,b) ((a>b)?a:b)
#define Fo(i,j,k) for(int i=j;i<=k;i++)
#define Fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
LL const Mxn=1e11,Mxnn=1e6;
LL N;LL Tag[Mxnn+9],Mu[Mxnn+9],Pri[Mxnn+9];
LL Sqrt3(LL N){
    LL L=0,R=sqrt(N),Mid;
    while(L!=R){
        Mid=(L+R+1)>>1;
        if(Mid*Mid*Mid<=N)L=Mid;
        else R=Mid-1;
    }
    return L;
}
LL Calc(LL N){
    LL Ans=0,II,JJ,KK,Tm,Tmp,Sum,NN=sqrt(N);
    Fo(d,1,NN){
        Tm=N/d/d;Sum=0;
        II=Sqrt3(Tm);
        Fo(i,1,II){
            JJ=sqrt(Tm/i);
            Fo(j,i+1,JJ){
                KK=Tm/i/j;
                Sum+=(j*6:0;

            }
        }
        Tmp=sqrt(Tm);
        Fo(i,1,Tmp)Sum+=(Tm/i/i-(Tm/i/i>=i))*4;
        Sum+=II*2;
        Ans+=Mu[d]*Sum;
    }
    return Ans/2;
}
int main(){
    freopen("d.in","r",stdin);
    freopen("d.out","w ",stdout);
    LL NN=sqrt(Mxn);
    Mu[1]=1;
    Fo(i,2,NN){
        if(!Tag[i])Pri[++Pri[0]]=i,Mu[i]=-1;
        Fo(j,1,Pri[0]){
            if(i*Pri[j]>NN)break;
            Tag[i*Pri[j]]=1;
            Mu[i*Pri[j]]=-Mu[i];
            if(i%Pri[j]==0){Mu[i*Pri[j]]=0;break;}
        }
    }
    LL L,R;scanf("%lld%lld",&L,&R);
    printf("%lld",Calc(R)-Calc(L-1));
    return 0;
}

你可能感兴趣的:(数论,51nod)