POJ-2452 Sticks Problem 二分+RMQ

题目链接:

https://cn.vjudge.net/problem/POJ-2452

题目大意:

给出一个数组a,求最大的j-i满足 i<j && a[i] ... a[j]中最大值为a[j],最小值为a[i]。

思路:

可以枚举i,然后二分找出满足的最大的j

首先,先二分找出最大的r,满足从a[i]到a[j]的最小值为a[i]。根据单调性可以二分找出来

然后从i-r找出最大值的下标就可以了。

二分的时候,需要多次求出区间最大最小值,用ST表预处理出来。

也可以用线段树,不过更慢。时间可以卡着过

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
 6 #define Max(a, b) (a) > (b) ? (a) : (b)
 7 #define Min(a, b) (a) < (b) ? (a) : (b)
 8 #define Mem(a) memset(a, 0, sizeof(a))
 9 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
10 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
11 using namespace std;
12 inline int read()
13 {
14     int x=0,f=1;char ch=getchar();
15     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
16     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
17     return x*f;
18 }
19 
20 typedef long long ll;
21 const int maxn = 50000 + 10;
22 const int MOD = 1000000007;//const引用更快,宏定义也更快
23 
24 int a[maxn];
25 int rmq_min[maxn][20], rmq_max[maxn][20];
26 int n;
27 
28 void ST_init()
29 {
30     for(int i = 1; i <= n; i++)rmq_max[i][0] = rmq_min[i][0] = a[i];//下标从1-n
31     for(int j = 1; (1 << j) <= n; j++)
32     {
33         for(int i = 1; i + (1 << j) - 1 <= n; i++)
34             rmq_min[i][j] = Min(rmq_min[i][j - 1], rmq_min[i + (1 << (j - 1))][j - 1]);
35     }
36     for(int j = 1; (1 << j) <= n; j++)
37     {
38         for(int i = 1; i + (1 << j) - 1 <= n; i++)
39             rmq_max[i][j] = Max(rmq_max[i][j - 1], rmq_max[i + (1 << (j - 1))][j - 1]);
40     }
41 }
42 inline int query_Min(int l, int r)
43 {
44     int k = 0;
45     while((1 << (k + 1)) <= r - l + 1)k++;
46     return Min(rmq_min[l][k], rmq_min[r - (1 << k) + 1][k]);
47 }
48 inline int query_Max(int l, int r)
49 {
50     int k = 0;
51     while((1 << (k + 1)) <= r - l + 1)k++;
52     return Max(rmq_max[l][k], rmq_max[r - (1 << k) + 1][k]);
53 }
54 int main()
55 {
56     while(scanf("%d", &n) != EOF)
57     {
58         for(int i = 1; i <= n; i++)a[i] = read();
59         ST_init();
60         int ans = -1;
61         for(int i = 1; i < n; i++)
62         {
63             int l = i, r = n, ansr = -1;
64             while(l <= r)//二分 找最右端满足区间最小值为a[i]的下标
65             {
66                 int mid = (l + r) / 2;
67                 if(query_Min(i, mid) == a[i])
68                     ansr = mid, l = mid + 1;
69                 else r = mid - 1;
70             }
71             if(ansr > i)//再次二分,找到最大值点的下标
72             {
73                 int tmp = query_Max(i, ansr);
74                 l = i, r = ansr;
75                 ansr = -1;
76                 while(l <= r)
77                 {
78                     int mid = (l + r) / 2;
79                     if(query_Max(i, mid) == tmp)r = mid - 1, ansr = mid;
80                     else l = mid + 1;
81                 }
82                 if(ansr > i)ans = Max(ans, ansr - i);
83             }
84         }
85         printf("%d\n", ans);
86     }
87     return 0;
88 }

 

posted @ 2018-08-30 20:41  _努力努力再努力x  阅读(366)  评论(0编辑  收藏  举报