HDU 3530 RMQ+twopointer/单调队列
2015-08-17 00:23
330 查看
题意: 给定一个序列, 让你寻找一个最长的区间,这个区间满足最大值减去最小值大于等于m小于等于k,求这个长度
但是悲剧 被卡了常数应该。。 复杂度nlogn不过常数大点。。
最后的two pointer这里为什么这样写。。 是因为这个函数是个单调的。。所以走一遍就可以得到答案。。主要还是单调的。需要仔细体会。
这里维护了两个单调队列,一个维护max另一个维护min,如果需要移除队首元素就比较一下这两个队列的队首的位置,当然先移除最远的那个了。。还是因为单调性。
1. RMQ + 二分
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; int n,m,k; int a[100100]; int dp1[101000][20]; int dp2[101000][20]; void init() { for(int i=1; i<=n; i++) dp1[i][0] = dp2[i][0] = a[i]; for(int j=1; j<=20; j++) for(int i=1; i+(1<<j)-1<=n; i++) { dp1[i][j] = max(dp1[i][j-1], dp1[i+(1<<(j-1))][j-1]); dp2[i][j] = min(dp2[i][j-1], dp2[i+(1<<(j-1))][j-1]); } } int get_max(int l, int r) { int k = log(r-l+1)/log(2); return max(dp1[l][k], dp1[r-(1<<k)+1][k]); } int get_min(int l, int r) { int k = log(r-l+1)/log(2); return min(dp2[l][k], dp2[r-(1<<k)+1][k]); } int ans = 0; void solve(int i) { int l = i; int r = n; int res1; while(l<=r) { int mid = (l+r)>>1; int maxn = get_max(i, mid); int minn = get_min(i, mid); if(maxn - minn <=k) { res1 = mid; l = mid+1; } else r = mid-1; } l = i; r = n; int res2; while(l<=r) { int mid = (l+r)>>1; int maxn = get_max(i, mid); int minn = get_min(i, mid); if(maxn - minn >= m) { res2 = mid; r = mid-1; } else l = mid+1; } if(res1 >= res2) ans = max(ans, res1 - res2 + 1); } int main() { while(~scanf("%d %d %d", &n, &m, &k)) { memset(dp1, -1, sizeof(dp1)); memset(dp2, 0x3f3f3f3f, sizeof(dp2)); for(int i=1; i<=n; i++) scanf("%d", &a[i]); init(); ans = 0; for(int i=1; i<=n; i++) solve(i); printf("%d\n", ans); } return 0; }
但是悲剧 被卡了常数应该。。 复杂度nlogn不过常数大点。。
2. RMQ + two pointer
#include <iostream>## 标题 ## #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; int n,m,k; int a[100100]; int dp1[101000][20]; int dp2[101000][20]; void init() { for(int i=1; i<=n; i++) dp1[i][0] = dp2[i][0] = a[i]; for(int j=1; j<=20; j++) for(int i=1; i+(1<<j)-1<=n; i++) { dp1[i][j] = max(dp1[i][j-1], dp1[i+(1<<(j-1))][j-1]); dp2[i][j] = min(dp2[i][j-1], dp2[i+(1<<(j-1))][j-1]); } } int get_max(int l, int r) { int k = log2(r-l+1); return max(dp1[l][k], dp1[r-(1<<k)+1][k]); } int get_min(int l, int r) { int k = log2(r-l+1); return min(dp2[l][k], dp2[r-(1<<k)+1][k]); } int ans = 0; void solve(int i) { int l = i; int r = n; int res1; while(l<=r) { int mid = (l+r)>>1; int maxn = get_max(i, mid); int minn = get_min(i, mid); if(maxn - minn <=k) { res1 = mid; l = mid+1; } else r = mid-1; } l = i; r = n; int res2; while(l<=r) { int mid = (l+r)>>1; int maxn = get_max(i, mid); int minn = get_min(i, mid); if(maxn - minn >= m) { res2 = mid; r = mid-1; } else l = mid+1; } if(res1 >= res2) ans = max(ans, res1 - res2 + 1); } int main() { while(~scanf("%d %d %d", &n, &m, &k)) { memset(dp1, -1, sizeof(dp1)); memset(dp2, 0x3f3f3f3f, sizeof(dp2)); for(int i=1; i<=n; i++) scanf("%d", &a[i]); init(); int l,r; l=1;ans=0; //l不用每次从1开始判,因为之前的l越小,r-l+1的值就越大。 for(int i=1;i<=n;i++) { r=i; if(l>r)continue; while(get_max(l,r)-get_min(l,r)>k)l++; //如果大于k,那么后面的r对于此时的l肯定不满足不大于k,所以必须l++; if(get_max(l,r)-get_min(l,r)>=m && get_max(l,r)-get_min(l,r)<=k)ans=max(ans,r-l+1); } printf("%d\n",ans); } return 0; }
最后的two pointer这里为什么这样写。。 是因为这个函数是个单调的。。所以走一遍就可以得到答案。。主要还是单调的。需要仔细体会。
3.单调队列
#include <bits/stdc++.h> using namespace std; int n,m,k; int a[1000100]; deque<int> q1; deque<int> q2; int main() { while(cin>>n>>m>>k) { q1.clear(); q2.clear(); for(int i=1; i<=n; i++) scanf("%d", &a[i]); int now = 1; int ans = 0; for(int i=1; i<=n; i++) { while(!q1.empty()&&a[q1.back()]<a[i]) q1.pop_back(); while(!q2.empty()&&a[q2.back()]>a[i]) q2.pop_back(); q1.push_back(i); q2.push_back(i); while(!q1.empty()&&!q2.empty()&&a[q1.front()] - a[q2.front()] > k) { if(q1.front() < q2.front()) { now = q1.front()+1; q1.pop_front(); } else { now = q2.front()+1; q2.pop_front(); } } if(!q1.empty()&&!q2.empty()&&a[q1.front()] - a[q2.front()] >= m) ans = max(ans, i - now +1); } cout<<ans<<endl; } return 0; }
这里维护了两个单调队列,一个维护max另一个维护min,如果需要移除队首元素就比较一下这两个队列的队首的位置,当然先移除最远的那个了。。还是因为单调性。
相关文章推荐
- 浅谈单调队列、单调栈
- 2015 Multi-University Training Contest 6 Solutions
- 通过 poj3368 问题讨论:RMQ问题的 tarjan_lca 求解
- sjtu online judge 1034 二哥的金链
- POJ3264-Balanced Lineup RMQ
- [BZOJ1499][NOI2005][DP+优化]瑰丽华尔兹
- [BZOJ2006][NOI2010][RMQ/主席树][二叉堆]超级钢琴
- hdu4193 hoj3107
- HDU3530
- RMQ问题
- 【bzoj1047】【单调队列】【HAOI2007】理想的正方形
- RMQ 模板
- [PKU3264]Balanced Lineup
- Balanced Lineup(RMQ)(POJ 3264)
- 2015 Multi-University Training Contest 1 Hdu 5289 Assignment
- HDU 3415 (单调队列优化DP)
- poj2823Sliding Window
- RMQ_Sparse Table & Segment Tree
- bzoj 1717: [Usaco2006 Dec] Milk Patterns
- 【Jason's_ACM_解题报告】Defense Lines