[BZOJ2820]YY的GCD|莫比乌斯反演

Description

神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
 
  题面依然很亲切,和之前不同的在于是所有质数
  然后把式子化一化,对莫比乌斯函数求一个奇怪的前缀和
  这里的时间复杂度比较神奇..
 
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 const int maxn = 10000010,maxp = 664580;
 5 int vis[maxn],prime[maxp],mu[maxn];
 6 long long sum[maxn];
 7 int min(int a,int b){if (a<b) return a;else return b;}
 8 void build(){
 9     memset(vis,1,sizeof(vis));
10     prime[0]=0;mu[1]=1;
11     for (int i=2;i<=maxn;i++){
12         if (vis[i]){
13             prime[++prime[0]] = i;
14             mu[i] = -1;
15         }
16         for (int j=1;j<=prime[0]&&i*prime[j]<=maxn;j++){
17             vis[i*prime[j]] = 0;
18             if (i%prime[j]==0){
19                 mu[i*prime[j]] = 0;
20                 break;
21             }
22             mu[i*prime[j]] = -mu[i];
23         }
24     }
25     memset(sum,0,sizeof(sum));
26     for (int i=1;i<=prime[i];i++)
27         for (int j=1;j*prime[i]<=maxn;j++) sum[j*prime[i]]+=mu[j];
28     for (int i=2;i<=maxn;i++) sum[i]+=sum[i-1];
29 }
30 
31 long long solve(int n,int m){
32     if (n>m){int tem=n;n=m;m=tem;}
33     int las;long long ans=0;
34     for (int i=1;i<=n;i=las+1){
35         las = min(n/(n/i),m/(m/i));
36         ans+=(sum[las]-sum[i-1])*(long long)(n/i)*(m/i);
37     }
38     return ans;
39 }
40 int main(){
41     build();
42     int test,n,m;
43     scanf("%d",&test);
44     while (test--){
45         scanf("%d%d",&n,&m);
46         printf("%lld\n",solve(n,m));
47     }
48 }

 

 
posted @ 2015-05-06 14:50  mjy0724  阅读(217)  评论(0编辑  收藏  举报