BZOJ 2820 YY的GCD 【莫比乌斯反演】

Description

神犇YY虐完数论后给傻×kAc出了一题
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对
kAc这种傻×必然不会了,于是向你来请教……

Hint

T = 10000

N, M <= 10000000

Solution

先不要虚,刚个正面把求和公式写出来

//此处膜了黄学长题解来

暴力写开是长成这样的

然后我们按照一般的莫比乌斯反演的用法一直往下推

发现是个最基础的莫比乌斯反演外面套了个枚举素数,√n*logn而已

然而看了看复杂度= =

已然炸掉了,BZOJ的评测机应该是跑不出来的

考虑一下怎么优化

之前我们曾用转化求和指标的方式,使用前缀和减少了枚举量

这里我们也尝试用同样的方式优化

用枚举k代替枚举pd

于是得到

同样前缀和之后分块

复杂度变回了O(√n)

  1 #include<map>
  2 #include<cmath>
  3 #include<ctime>
  4 #include<queue>
  5 #include<stack>
  6 #include<cstdio>
  7 #include<climits>
  8 #include<iomanip>
  9 #include<cstring>
 10 #include<cstdlib>
 11 #include<iostream>
 12 #include<algorithm>
 13  
 14 #define maxp 10000000
 15 #define maxn 10000000+5
 16 #define set(a,b) memset(a,(b),sizeof(a))
 17 #define fr(i,a,b) for(ll i=(a),_end_=(b);i<=_end_;i++)
 18 #define rf(i,b,a) for(ll i=(a),_end_=(b);i>=_end_;i--)
 19 #define fe(i,a,b) for(int i=first[(b)],_end_=(a);i!=_end_;i=s[i].next)
 20 #define fec(i,a,b) for(int &i=cur[(b)],_end_=(a);i!=_end_;i=s[i].next)
 21  
 22 using namespace std;
 23  
 24 typedef long long ll;
 25  
 26 int prime[maxn],pri[maxn],miu[maxn],tot=0;;
 27 ll F[maxn],ans;
 28 int T,n,m;
 29  
 30 void read()
 31 {
 32 #ifndef ONLINE_JUDGE
 33   freopen("2820.in","r",stdin);
 34   freopen("2820.out","w",stdout);
 35 #endif
 36   //cin >> T ;
 37   scanf("%d",&T);
 38 }
 39  
 40 void write()
 41 {}
 42  
 43 void print()
 44 {
 45   //cout << ans << endl ;
 46   printf("%lld\n",ans);
 47 }
 48  
 49 void get()
 50 {
 51   miu[1]=1;
 52   fr(i,2,maxp){
 53     if( !prime[i] ) pri[++tot]=i,miu[i]=-1;
 54     int j=1;
 55     while( j<=tot && pri[j]*i<=maxp ){
 56       prime[i*pri[j]]=1;
 57       if( i%pri[j]==0 ){
 58     miu[i*pri[j]]=0;
 59     break ;
 60       }
 61       miu[i*pri[j]]=-miu[i];
 62       j++;
 63     }
 64   }
 65   fr(i,1,tot)
 66     fr(j,1,maxp/pri[i])
 67     F[j*pri[i]]+=miu[j];
 68   fr(i,1,maxp)
 69     F[i]+=F[i-1];
 70 }
 71  
 72 ll calc(int x,int y)
 73 {
 74   if( x>y ) swap(x,y);
 75   ll res=0;
 76   int i=1,pos;
 77   while( i<=x ){
 78     //pos=min(x/(x/i),y/(y/i));
 79     pos=min(x*i/(x+i),y*i/(y+i));
 80     res+=(F[pos]-F[i-1])*(x/i)*(y/i);
 81     i=pos+1;
 82   }
 83   return res;
 84 }
 85  
 86 void work()
 87 {
 88   get();
 89   while( T-- ){
 90     //cin >> n >> m ; 
 91     scanf("%d%d",&n,&m);
 92     ans=calc(n,m);
 93     print();
 94   }
 95 }
 96  
 97 int main()
 98 {
 99   read();
100   work();
101   write();
102   return 0;
103 }

 

posted @ 2015-07-01 21:24  ST_Saint  阅读(133)  评论(0编辑  收藏  举报