【莫比乌斯反演】BZOJ2820 YY的GCD

Description

  求有多少对(x,y)的gcd为素数,x<=n,y<=m。n,m<=1e7,T<=1e4。

 

Solution

  因为题目要求gcd为素数的,那么我们就只考虑素数mu的贡献就行了

  对于p,对于k*p的贡献是mu[k]

  然后加上整除分块优化就行了

  p可以筛完素数处理,处理复杂度为O(n/log*log)正好为O(n)

 

Code

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 
 7 const int maxn=1e7+5;
 8 
 9 int flag[maxn],prime[maxn],mu[maxn],cnt;
10 ll sum[maxn];
11 int n,m;
12 
13 void getmu(){
14     mu[1]=1;
15     for(int i=2;i<=1e7;i++){
16         if(!flag[i]){
17             prime[++cnt]=i;
18             mu[i]=-1;
19         }
20         for(int j=1;i*prime[j]<=1e7&&j<=cnt;j++){
21             flag[i*prime[j]]=1;
22             if(i%prime[j]==0){
23                 mu[i*prime[j]]=0;
24                 break;
25             }
26             mu[i*prime[j]]=-mu[i];
27         }
28     }
29     for(int i=1;i<=cnt;i++)
30         for(int j=prime[i];j<=1e7;j+=prime[i])
31             sum[j]+=mu[j/prime[i]];
32     for(int i=1;i<=1e7;i++)
33         sum[i]+=sum[i-1];
34 }
35 
36 int main(){
37     getmu();
38     int T;
39     scanf("%d",&T);
40     while(T--){
41         scanf("%d%d",&n,&m);
42         if(n>m) swap(n,m);
43         ll ans=0;
44         for(int i=1,pos=1;i<=n;i=pos+1){
45             pos=min(n/(n/i),m/(m/i));
46             ans+=(sum[pos]-sum[i-1])*(n/i)*(m/i);
47         }
48         printf("%lld\n",ans);
49     }
50     return 0;
51 }

 

posted @ 2015-06-24 13:15  CyanNode  阅读(217)  评论(0编辑  收藏  举报