BZOJ 3994: [SDOI2015]约数个数和

参考博客:bzoj3994/洛谷P3327 莫比乌斯反演
代码:

#include<cstdio>
#include<algorithm>
using namespace std;

typedef long long ll;
const int maxn=50000+100;

ll F[maxn];  //F[i] 表示i的约数个数 
int num[maxn];  //num[i] 表示i最小素因子的指数 
int mu[maxn];
int prime[maxn],tot;
bool isprime[maxn];

void init(){

    for(int i=0;i<maxn;i++) isprime[i]=true;
    isprime[0]=isprime[1]=false;
    tot=0;
    F[1]=1;
    mu[1]=1;
    for(int i=2;i<maxn;i++){

        if(isprime[i]) prime[tot++]=i,F[i]=2,num[i]=1,mu[i]=-1;
        for(int j=0;j<tot && i*prime[j]<maxn;j++){

            isprime[i*prime[j]]=false;
            if(i%prime[j]) F[i*prime[j]]=F[i]*2,num[i*prime[j]]=1,mu[i*prime[j]]=-mu[i];
            else{

                F[i*prime[j]]=F[i]/(num[i]+1)*(num[i]+2);
                num[i*prime[j]]=num[i]+1;
                break;
            }
        }
    }
    for(int i=2;i<maxn;i++) F[i]+=F[i-1],mu[i]+=mu[i-1];
}

int main(){

    init();
    int T;
    scanf("%d",&T);
    while(T--){

        int n,m;
        scanf("%d%d",&n,&m);
        int ind;
        ll res=0;
        if(n>m) swap(n,m); 
        for(int i=1;i<=n;i=ind+1){

           ind=min(n/(n/i),m/(m/i));
           res+=(ll)(mu[ind]-mu[i-1])*F[n/i]*F[m/i];
        }
        printf("%lld\n",res);
   }
} 

猜你喜欢

转载自blog.csdn.net/qq_37960603/article/details/81261180