Bzoj3994 [SDOI2015]约数个数和

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 857  Solved: 586

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

 

Source

 

数学问题 莫比乌斯反演 脑洞题

这里讲得很好http://www.cnblogs.com/mmlz/p/4442452.html

 

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<vector>
 8 #define LL long long
 9 using namespace std;
10 const int mxn=50010;
11 int read(){
12     int x=0,f=1;char ch=getchar();
13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
15     return x*f;
16 }
17 int pri[mxn],cnt=0;
18 int mu[mxn],d[mxn],f[mxn];
19 //mu:莫比乌斯函数 d[x]:x的最小质因子的次数 f[x]:x的约数个数 
20 int smm[mxn];
21 bool vis[mxn];
22 void init(){
23     mu[1]=1;f[1]=1;
24     for(int i=2;i<mxn;i++){
25         if(!vis[i]){
26             mu[i]=-1;
27             pri[++cnt]=i;
28             d[i]=1;    f[i]=2;
29         }
30         for(int j=1;j<=cnt && (LL)pri[j]*i<mxn;j++){
31             int x=pri[j]*i;
32             vis[x]=1;
33             if(i%pri[j]==0){//i是x的因数,对f[x]的贡献为(d[i]+2)
34                 mu[x]=0;
35                 f[x]=f[i]/(d[i]+1)*(d[i]+2);
36                 d[x]=d[i]+1;
37                 break;
38             }
39             mu[x]=-mu[i];
40             f[x]=f[i]*2;
41             d[x]=1;
42         }
43     }
44     for(int i=1;i<mxn;i++){
45         smm[i]=smm[i-1]+mu[i];
46         f[i]+=f[i-1];
47     }
48     return;
49 }
50 LL calc(int n,int m){
51     if(n>m)swap(n,m);
52     LL res=0;int pos;
53     for(int i=1;i<=n;i=pos+1){
54         int x=n/i,y=m/i;
55         pos=min(n/x,m/y);
56         res+=(LL)(smm[pos]-smm[i-1])*(LL)f[x]*f[y];
57     }
58     return res;
59 }
60 int n,m;
61 int main(){
62     int i,j;
63     init();
64     int T=read();
65     while(T--){
66         n=read();m=read();
67         printf("%lld\n",calc(n,m));
68     }
69     return 0;
70 }

 

posted @ 2017-03-22 21:43  SilverNebula  阅读(207)  评论(0编辑  收藏  举报
AmazingCounters.com