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:\n" , ca);
74         scanf("%d" , &q);
75         while(q--) {
76             scanf("%d %d" , &u , &v);
77             int gcd = rmq(u , v);
78             printf("%d %lld\n" , gcd , mp[gcd]);
79         }
80     }
81     return 0;
82 }
时间: 2024-08-03 03:40:06

HDU 5726 GCD (RMQ + 二分)的相关文章

hdu 5726 GCD 倍增+ 二分

题目链接 给n个数, 定义一个运算f[l,r] = gcd(al, al+1,....ar). 然后给你m个询问, 每次询问给出l, r. 求出f[l, r]的值以及有多少对l', r' 使得f[l, r] = f[l', r']. 第一个很简单, 用倍增的思想就可以了. 然后是第二个, 我们枚举每一个左端点i, 显然f[i, j]是只降不增的. 那么我们可以二分找到所有使得f[i, j]下降的值j. 因为gcd每次至少变为原来的二分之一, 而ai最大为1e9. 所以最多只有log2(1e9)个

HDU 5726 GCD 区间GCD=k的个数

GCD Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2742    Accepted Submission(s): 980 Problem Description Give you a sequence of N(N≤100,000) integers : a1,...,an(0<ai≤1000,000,000). There ar

HDU 5726 GCD(DP)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5726 [题目大意] 给出数列An,对于询问的区间[L,R],求出区间内数的GCD值,并且求出GCD值与其相等的区间总数 [题解] 首先,固定一个区间的右端点,利用GCD的递减性质,可以求出GCD相等的区间左端点的范围,将其范围的左右端点保存下来,同时,对于每个新产生的区间,以其GCD值为下标的MAP值+1,最后对于每个询问,在其右端点保存的范围中查找,获得其GCD值,同时在MAP中获取该GCD值

HDU - 5289 Assignment (RMQ+二分)

题目链接: Assignment  题意: 给出一个数列,问其中存在多少连续子序列,使得子序列的最大值-最小值<k. 题解: RMQ先处理出每个区间的最大值和最小值(复杂度为:n×logn),相当于求出了每个区间的最大值-最小值.那么现在我们枚举左端点,二分右端点就可以在n×logn×logn的时间内过. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX_N = 1e5+9; 4 int vec[MAX_N]

HDU 5726 GCD

传送门 GCD Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem DescriptionGive you a sequence of $N(N≤100,000)$ integers : $a_1,\cdots,a_n(0<a_i≤1000,000,000)$. There are $Q(Q≤100,000)$ queries. For each query $l

GCD (hdu 5726)

GCD Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1497    Accepted Submission(s): 483 Problem Description Give you a sequence of N(N≤100,000) integers : a1,...,an(0<ai≤1000,000,000). There ar

hdu 5289 Assignment(2015多校第一场第2题)RMQ+二分(或者multiset模拟过程)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289 题意:给你n个数和k,求有多少的区间使得区间内部任意两个数的差值小于k,输出符合要求的区间个数 思路:求出区间的最大最小值,只要他们的差值小于k,那么这个区间就符合要求,但是由于n较大,用暴力一定超时,所以就要用别的方法了:而RMQ是可以求区间的最值的,而且预处理的复杂度只有O(nlogn),而查询只是O(1)处理,这样相对来说节约了时间,再根据右端点来二分枚举左端点(其实不用二分好像更快,估

HDU 5089 Assignment(rmq+二分 或 单调队列)

Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 557    Accepted Submission(s): 280 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fr

hdu 4185 Oil Skimming(二分匹配)

Oil Skimming Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 883    Accepted Submission(s): 374 Problem Description Thanks to a certain "green" resources company, there is a new profitable