POJ_2452 Sticks Problem 【ST表 + 二分】

一、题目

  Sticks Problem

二、分析

  对于$i$和$j$,并没有很好的方法能同时将他们两找到最优值,所以考虑固定左端点$i$。

  固定左端点后,根据题意,$a[i]$是最小值,那么现在的问题就转化成了求以$a[i]$为左端点最小值的范围内,找到一个最大值$a[j]$的$j$,然后相减就是以$i$为左端点的最优值。

  然后枚举$i$,找到最大的$j-i$即可。

  如何找$j$,预先用ST表预处理好最大值最小值,然后先找以$i$为最小值的管辖范围(二分找,因为如果当前位置$pos$如果不满足,那么$j$肯定在$pos$的左边,反之可能在右边),再用ST表在这个范围内找到最大的$j$即可。

三、AC代码

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 
 8 using namespace std;
 9 #define ll long long
10 #define Min(a,b) ((a)>(b)?(b):(a))
11 #define Max(a,b) ((a)>(b)?(a):(b))
12 const int MAXN = 5e4 + 13;
13 int N, a[MAXN], STmax[MAXN][30], STmin[MAXN][30];
14 int Logn[MAXN];
15 
16 void pre_log()
17 {
18     Logn[1] = 0, Logn[2] = 1;
19     for(int i = 3; i <= MAXN; i++) {
20         Logn[i] = Logn[i/2] + 1;
21     }
22 }
23 
24 void pre_st()
25 {
26     for(int i = 1; i <= N; i++) STmax[i][0] = i, STmin[i][0] = i;
27     int k = Logn[N];
28     for(int j = 1; j <= k; j++) {
29         for(int i = 1; i + (1<<j) - 1 <= N; i++) {
30             if(a[STmin[i][j-1]] < a[STmin[i+(1<<(j-1))][j-1]]) STmin[i][j] = STmin[i][j-1];
31             else STmin[i][j] = STmin[i+(1<<(j-1))][j-1];
32             if(a[STmax[i][j-1]] > a[STmax[i+(1<<(j-1))][j-1]]) STmax[i][j] = STmax[i][j-1];
33             else STmax[i][j] = STmax[i+(1<<(j-1))][j-1];
34         }
35     }
36 }
37 
38 int query_min(int l, int r)
39 {
40     // int k = log(1.0*(r - l + 1))/log(2.0);
41     int k = Logn[r - l + 1];
42     if(a[STmin[l][k]] > a[STmin[r-(1<<k)+1][k]])  return STmin[r-(1<<k)+1][k];
43     else return STmin[l][k];
44 }
45 
46 int query_max(int l, int r)
47 {
48     int k = log(1.0*(r - l + 1))/log(2.0);
49     if(a[STmax[l][k]] < a[STmax[r-(1<<k)+1][k]])  return STmax[r-(1<<k)+1][k];
50     else return STmax[l][k];
51 }
52 
53 int query(int l, int r)
54 {
55     int p = l;
56     while(l < r) {
57         int mid = (l+r+1)>>1;
58         if(query_min(p, mid) == p)  l = mid;
59         else r = mid-1;
60     }
61     return l;
62 }
63 
64 int main()
65 {
66     pre_log();
67     while(scanf("%d", &N) != EOF) {
68         for(int i = 1; i <= N; i++) {
69             scanf("%d", &a[i]);
70         }
71         pre_st();
72         int ans = -1;
73         for(int i = 1; i < N; i++) {
74             //先以i为最小值进行查找最大的管辖范围
75             //再求范围内的最大j
76             int j = query_max(i, query(i, N));
77             if(j - i == 0)
78                 continue;
79             else 
80                 ans = Max(ans, j - i);
81         }
82         printf("%d\n", ans);
83     }
84     return 0;
85 }

 

posted @ 2019-08-28 12:55  Dybala21  阅读(142)  评论(0编辑  收藏  举报