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 }

 

posted @ 2016-04-19 19:02  Naturain  阅读(276)  评论(0编辑  收藏  举报