hdu 5726 GCD

题意:

给出一个数组,每次询问区间[l,r]的gcd是多少,并且这个数组有多少个连续的区间的gcd和[l,r]的gcd相等。

思路:

区间询问RMQ问题,可以用st表解决,预处理的时间是O(nlogn),一次查询的时间是O(logn)。

关键是第二个问题,如何找出这些区间的数量。

如果固定区间的左端点,那么随着区间长度的增大,gcd肯定是非递增的,减少的话一定是每次至少减少1/2,所以一个区间内的gcd最多有log(1e9)个。

所以固定左端点,二分当前的gcd能达到的最远的右端点的位置,然后加到一个map当中进行维护,这也是一个预处理,那么每次就可以o(logn)进行回答。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <math.h>
 5 #include <map>
 6 using namespace std;
 7 typedef long long ll;
 8 const int N = 1e5 + 10;
 9 int a[N],dp[N][32];
10 map<int,ll> mmp;
11 int gcd(int x,int y)
12 {
13     return y ? gcd(y,x%y) : x; 
14 }
15 void init(int n)
16 {
17     mmp.clear();
18     for (int i = 0;i < n;i++)
19     {
20         dp[i][0] = a[i];
21     }
22     int bitn = (int)(log(n)/log(2.0));
23     for (int j = 1;j <= bitn;j++)
24     {
25         for (int i = 0;i < n;i++)
26         {
27             if (i + (1 << j) - 1 >= n) break;
28             dp[i][j] = gcd(dp[i][j-1],dp[i+(1 << (j-1))][j-1]);
29         }
30     }
31 }
32 int que(int l,int r)
33 {
34     int k = (int)(log(r-l+1.0) / log(2.0));
35     return gcd(dp[l][k],dp[r-(1<<k)+1][k]);
36 }
37 int main()
38 {
39     int T;
40     scanf("%d",&T);
41     int kase = 0;
42     while (T--)
43     {
44         int n;
45         scanf("%d",&n);
46         for (int i = 0;i < n;i++) scanf("%d",&a[i]);
47         printf("Case #%d:\n",++kase);
48         init(n);
49         for (int i = 0;i < n;i++)
50         {
51             int j = i;
52             while (j < n)
53             {
54                 int tmp = que(i,j);
55                 int l = j,r = n;
56                 while (r - l > 1)
57                 {
58                     int mid = (l + r) >> 1;
59                     if (que(i,mid) == tmp) l = mid;
60                     else r = mid;
61                 }
62                 mmp[tmp] += l - j + 1;
63                 j = l + 1;
64             }
65         }
66         int q;
67         scanf("%d",&q);
68         while (q--)
69         {
70             int l,r;
71             scanf("%d%d",&l,&r);
72             l--,r--;
73             int ans = que(l,r);
74             printf("%d %lld\n",ans,mmp[ans]);
75         }
76     }
77     return 0;
78 }

 

posted @ 2018-05-19 00:15  qrfkickit  阅读(230)  评论(0编辑  收藏  举报