BZOJ2694 Lcm 【莫比乌斯反演】

 

BZOJ2694 Lcm


Description

 

Input

一个正整数T表示数据组数
接下来T行 每行两个正整数 表示N、M

Output

T行 每行一个整数 表示第i组数据的结果

Sample Input

4
2 4
3 3
6 5
8 3

Sample Output

24
28
233
178

HINT

T <= 10000
N, M<=4000000


文章链接:https://www.cnblogs.com/dream-maker-yk/p/9676383.html

 


#include<bits/stdc++.h>
using namespace std;
#define N 4000010
#define LL long long
int T,n,m,tot=0,Mod=1;
int pri[N],mu[N];
LL F[N],C[N];
bool mark[N]={0};
void init(){
    for(int i=1;i<=30;i++)Mod*=2;
    mu[1]=1;
    for(int i=2;i<N;i++){
        if(!mark[i])pri[++tot]=i,mu[i]=-1;
        for(int j=1;j<=tot&&i*pri[j]<N;j++){
            mark[i*pri[j]]=1;
            if(i%pri[j]==0)mu[i*pri[j]]=0;
            else mu[i*pri[j]]=-mu[i];
        }
    }
    for(int i=1;i<N;i++)
        for(int j=1;i*j<N;j++)
            if(mu[j])F[i*j]+=mu[i]*i;
    for(int i=1;i<N;i++)F[i]=(1ll*F[i]*i+F[i-1]+Mod)%Mod;
    for(int i=1;i<N;i++)C[i]=(1ll*(i+1)*i/2)%Mod;
}
int main(){
    init();
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        LL ans=0;
        int up=min(n,m);
        for(int i=1,j;i<=up;i=j+1){
            j=min(n/(n/i),m/(m/i));
            ans=(ans+(F[j]-F[i-1])*C[n/i]*C[m/i]%Mod+Mod)%Mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2018-06-20 12:21  Dream_maker_yk  阅读(125)  评论(0编辑  收藏  举报