首页 > 其他 > 详细

bzoj:3994:vijos1949: [SDOI2015]约数个数和

时间:2015-12-29 15:59:19      阅读:162      评论:0      收藏:0      [点我收藏+]

Description

 设d(x)为x的约数个数,给定N、M,求  技术分享
 

 

Input

输入文件包含多组测试数据。

第一行,一个整数T,表示测试数据的组数。
接下来的T行,每行两个整数N、M。
 

Output

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

 

Sample Input

2
7 4
5 6

Sample Output

110
121

HINT

 

 1<=N, M<=50000


1<=T<=50000
 
技术分享
 
数论……终于还是的在神犇博客的帮助下才写得出……T_T……
最后推出一个式子ans=sigma(miu(i)*f(n/i)*f(m/i)),其中f(m/i)为d数组的前缀和……还有个优化是把n/i卡成数段再加起来……
 
#include<cstdio>
#include<algorithm>
using namespace std;
int t,n,m,p[10001],u[50001],s[50001],f[50001],num=0,o,an[22],xn,xm;
long long ans;
bool bo[50001];
char ch;
inline int min(int x,int y){return x<y?x:y;}
inline int read(){
    o=0;ch=getchar();
    while (ch<0||ch>9) ch=getchar();
    while (ch>=0&&ch<=9) o=o*10+ch-48, ch=getchar();
    return o;
}
int main(){
    scanf("%d",&t);
    u[1]=1;s[1]=1;
    register int i,j;
    for (i=2;i<=50000;i++){
        if (!bo[i]) p[num++]=i,u[i]=-1,s[i]=2,f[i]=1;
        for (j=0;j<num;j++){
            o=i*p[j];
            if (o>50000) break;
            bo[o]=1;
            if (i%p[j]) u[o]=-u[i],s[o]=s[i]*2,f[o]=1;else{
                u[o]=0;
                s[o]=s[i]/(f[i]+1)*(f[i]+2);
                f[o]=f[i]+1;
            }
        }
        s[i]+=s[i-1];u[i]+=u[i-1];
    }
    while(t--){
        n=read();m=read();
        if (n>m) swap(n,m);
        ans=0;
        for (i=1;i<=n;i=j+1) xn=n/i,xm=m/i,j=min(n/xn,m/xm),ans+=((long long)((u[j]-u[i-1])*s[xn])*s[xm]);
        printf("%lld\n",ans);
    }
}

 

 

bzoj:3994:vijos1949: [SDOI2015]约数个数和

原文:http://www.cnblogs.com/Enceladus/p/5085640.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!