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 }