SDOI2015 约数个数和

Description

 

Input

输入文件包含多组测试数据。
第一行,一个整数T,表示测试数据的组数。
接下来的T行,每行两个整数N、M。

Output

T行,每行一个整数,表示你所求的答案。
 

Sample Input

2
7 4
5 6

Sample Output

110
121
 

Data Constraint

 

解法:莫比乌斯反演,话说SD去年好像也出了题反演题

贴大神的blog题解

http://blog.codebursts.com/bzoj3994/

 

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;
typedef long long ll;

ll num[50011],mu[50011],ans;
int pri[50011],np[50011];
bool p[50011];
int dt,tj,i,j,n,m;

void prepare()
{
    ll tz;
    int i,j,lim,tot;
    lim=50000;
    tot=0;
    memset(p,true,sizeof(p));
    num[1]=1;
    mu[1]=1;
    for(i=2;i<=lim;i++){
        if(p[i]){
            pri[++tot]=i;
            num[i]=2;
            np[i]=1;
            mu[i]=-1;
        }
        for(j=1;j<=tot;j++){
            tz=(ll)pri[j]*i;
            if(tz>lim)break;            
            p[pri[j]*i]=false;
            if(i%pri[j]==0){
                np[pri[j]*i]=np[i]+1;
                num[pri[j]*i]=num[i]/(np[i]+1)*(np[i]+2);
                mu[pri[j]*i]=0;
                break;
            }
            np[pri[j]*i]=1;
            num[pri[j]*i]=num[i]*2;
            mu[pri[j]*i]=-mu[i];
        }
    }
    for(i=1;i<=lim;i++){
        num[i]+=num[i-1];
        mu[i]+=mu[i-1];
    }
}

int main()
{
    scanf("%d",&dt);
    prepare();
    for(tj=1;tj<=dt;tj++){
        scanf("%d%d",&n,&m);
        if(n>m)swap(n,m);
        ans=0;
        for(i=1,j;i<=n;i=j+1){
            j=min(n/(n/i),m/(m/i));
            ans+=1ll*num[n/i]*num[m/i]*(mu[j]-mu[i-1]);
        }
        printf("%lld\n",ans);
    }
}

 

posted on 2015-04-21 21:58  razorjxt  阅读(447)  评论(0编辑  收藏  举报