知识点:尺取法,单调队列
难度:5
这个题的难度感觉高了,给个4应该比较合理,这种题看上去有很多做法,各种数据结构好像都行,我用的是我一眼看上去的方法,首先的想法就是尺取,对第一个区间进行尺取,但是我们还要维护和第一个序列相同的区间的第二个序列的最值,一开始想着用st表,但是我不会,看了看题解,发现可以使用单调队列
做了这个题对单调队列的理解又深了一点,单调队列不只是能解决之前固定滑动窗口最值的问题,我们这个问题只有一个窗口,大小是可以变的,单调队列同样可以来维护这个区间的最值,因为这里只需要它来维护这一个区间,就是我们尺取的区间,就算窗口怎么变,单调队列出队,入队的操作什么的都还是和原来一样的,只要是连续的窗口,那么就可以用单调队列来维护,今天是第一次这么用单调队列,打破了思维的束缚
总的思路就是我们用尺取法在第一个序列上面,用单调队列维护第二个序列的最值,区间就是尺取的区间,然后仅有的难度就是尺取的写法了,这里一旦第一个序列的区间和大于等于m,那么我们就要退出了,因为它要的是区间最大值最小能有多少,多加进去元素不会使答案变的更好,反而可能使答案变差,所以这就是尺取的写法
看了看题解,可以用二分,可以用各种数据结构,但是我觉得我这个方法算是不错的了,还有就是需要注意溢出的问题
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int main() {
int n;
long long m;
cin >> n >> m;
int a[N], b[N];
for (int i = 1; i <= n; i++) {
cin >> a[i] >> b[i];
}
int l = 1, r = 1;
long long sum = 0;
int ans = 1e9;
deque<int> q;
while (true) {
while (r <= n && sum < m) {
while (!q.empty() && b[r] >= b[q.back()]) q.pop_back();
q.push_back(r);
sum += (long long) a[r++];
}
if (sum < m) break;
while (l <= n && sum >= m) {
ans = min(ans, b[q.front()]);
if (!q.empty() && q.front() == l) q.pop_front();
sum -= (long long) a[l++];
}
}
cout << ans;
return 0;
}