HDU 5726 GCD (RMQ + 二分)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5726

给你n个数,q个询问,每个询问问你有多少对l r的gcd(a[l] , ... , a[r]) 等于的gcd(a[l'] ,..., a[r'])。

先用RMQ预处理gcd,dp[i][j] 表示从i开始2^j个数的gcd。

然后用map存取某个gcd所对应的l r的数量。

我们可以在询问前进行预处理,先枚举i,以i为左端点的gcd(a[i],..., a[r])的种类数不会超过log2(n),gcd呈单调不增性。(因为gcd值每次变化,至少除以2)

所以所有的gcd的种类个数最多就nlog2(n)。

明白之后,我们可以枚举i为左端点固定,然后二分一下右端点,计算每种gcd的数量。

大概理解之后就可以敲了,然后就是细节问题。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <string>
 6 #include <cstdio>
 7 #include <vector>
 8 #include <ctime>
 9 #include <cmath>
10 #include <queue>
11 #include <set>
12 #include <map>
13 using namespace std;
14 #define Fill(x, y) memset((x), (y), sizeof(x))
15 #define Rep(i, x, y) for(int i = x; i <= y; ++i)
16 #define Dow(i, x, y) for(int i = x; i >= y; --i)
17 typedef long long LL;
18 typedef pair <int, int> P;
19 typedef pair <LL, LL> PLL;
20 const LL mod = 1e9 + 7;
21 const LL inf = 1e18;
22 const int N = 1e5 + 10;
23 int GCD(int a, int b) {
24     return b ? GCD(b, a % b) : a;
25 }
26 
27 int dp[N][20];
28 map <int , LL> mp;
29 
30 void ST(int n) {
31     for(int k = 1 ; k < 19 ; ++k) {
32         for(int i = 1 ; i + (1 << k) - 1 <= n ; ++i) {
33             dp[i][k] = GCD(dp[i][k - 1] , dp[i + (1 << (k - 1))][k - 1]);
34         }
35     }
36 }
37 
38 int rmq(int l , int r) {
39     int k = log2(r - l + 1);
40     return GCD(dp[l][k] , dp[r - (1 << k) + 1][k]);
41 }
42 
43 int main()
44 {
45     int t , n , q , u , v;
46     scanf("%d" , &t);
47     for(int ca = 1 ; ca <= t ; ++ca) {
48         scanf("%d" , &n);
49         for(int i = 1 ; i <= n ; ++i)
50             scanf("%d" , &dp[i][0]);
51         ST(n);
52         mp.clear();
53         for(int i = 1 ; i <= n ; ++i) {
54             int l , r , temp = i , gcd = dp[i][0] , s = i;
55             do {
56                 l = temp , r = n;
57                 s = l , gcd = rmq(i , s);
58                 while(l <= r) {
59                     int mid = (l + r) / 2;
60                     temp = mid;
61                     if(rmq(i , mid) < gcd) {
62                         r = mid - 1;
63                         temp = mid - 1;
64                     }
65                     else {
66                         l = mid + 1;
67                     }
68                 }
69                 mp[gcd] += (LL)(temp - s + 1);
70                 temp++;
71             }while(temp <= n);
72         }
73         printf("Case #%d:
" , ca);
74         scanf("%d" , &q);
75         while(q--) {
76             scanf("%d %d" , &u , &v);
77             int gcd = rmq(u , v);
78             printf("%d %lld
" , gcd , mp[gcd]);
79         }
80     }
81     return 0;
82 }
原文地址:https://www.cnblogs.com/Recoder/p/5693190.html