BZOJ--2301(莫比乌斯反演,优化)
2016-04-19 17:43:45
题意:对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k。
思路:BZOJ的题,需要优化的莫比乌斯,F(d) = number of gcd(x,y) , (d|gcd(x,y)) ; f(d) = number of gcd(x,y)=d ===> f(d) = Sigma( mu(m/d) * F(m) ) , (d|m)
那么对于每个询问,我们就需要累加 F(m) 效率较差,F(m) = (b / m - (a - 1) / m)) * (d / m - (c - 1) / m) ,1 <= m <= bound ,考虑到 x / m 在 m 取一定范围时,答案都是一样的。
对于 x / y = k ,当 y ∈ [ x / (k+1) + 1, x / k ] 时等式成立,因此我们可以计算出 mu 数组的前缀和,分段来计算答案,对于 x / m 答案一样的为一段。
我们可以将询问分成四个部分:
1:1 <= x <= b , 1 <= y <= d
2:1 <= x <= a - 1 , 1 <= y <= d
3:1 <= x <= b , 1 <= y <= c - 1
4:1 <= x <= a - 1 , 1 <= y <= c - 1
那么最终的询问答案就为:ans1 - ans2 - ans3 + ans4,对于每个答案可以用上面的分段方法来加速。
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <time.h> 5 #include <math.h> 6 #include <vector> 7 #include <map> 8 #include <set> 9 #include <stack> 10 #include <queue> 11 #include <string> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 16 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 17 #define MEM(a,b) memset(a,b,sizeof(a)) 18 #define MP(a,b) make_pair(a,b) 19 #define PB push_back 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const double eps = 1e-8; 24 const int INF = (1 << 30) - 1; 25 const int MAXN = 50010; 26 27 int mu[MAXN]; 28 int vis[MAXN],prime[MAXN],pcnt; 29 int sum[MAXN]; 30 31 void Mu_pre(){ 32 mu[1] = 1; 33 pcnt = 0; 34 memset(vis,0,sizeof(vis)); 35 for(int i = 2; i < MAXN; ++i){ 36 if(!vis[i]){ 37 prime[++pcnt] = i; 38 mu[i] = -1; 39 } 40 for(int j = 1; j <= pcnt && i * prime[j] < MAXN; ++j){ 41 vis[i * prime[j]] = 1; 42 if(i % prime[j]) mu[i * prime[j]] = -mu[i]; 43 else{ 44 mu[i * prime[j]] = 0; 45 break; 46 } 47 } 48 } 49 for(int i = 1; i < MAXN; ++i) sum[i] = sum[i - 1] + mu[i]; 50 } 51 52 ll Cal(int a,int b){ 53 int top = min(a,b); 54 ll res = 0; 55 for(int i = 1; i <= top; ++i){ 56 int j = min(a / (a / i),b / (b / i)); 57 res += 1ll * (sum[j] - sum[i - 1]) * (a / i) * (b / i); 58 i = j; 59 } 60 return res; 61 } 62 63 int main(){ 64 Mu_pre(); 65 int T; 66 int a,b,c,d,k; 67 scanf("%d",&T); 68 while(T--){ 69 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 70 ll ans = Cal(b / k,d / k) - Cal((a - 1) / k,d / k) 71 - Cal(b / k,(c - 1) / k) + Cal((a - 1) / k,(c - 1) / k); 72 printf("%lld\n",ans); 73 } 74 return 0; 75 }