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 }
越努力,越幸运