CodeForces - 6E Exposition(尺取法+multiset)

CF6E Exposition

题目大意:

给一个\(n\)个元素的序列,从中挑出最长的子串,要求子串中元素差的最大值不超过\(k\)。问有几个最长子串,子串长度,以及这几个子串的起始、终止位置。

思路:

很容易想到尺取法。

我们使用\(multiset\)来完成对维护尺取的区间,因为\(multiset\)具有有序性和可充分性,而且在默认的情况下,该容器内的元素是使\(<\)运算符比较大小,也就是容器内部按升序排列。所以我们可以通过\(crbegin()\)\(cbegin()\)分别取出容器内的最大值和最小值进行模拟。

值得一提的是,在模拟单调队列的弹出操作时,我们使用

\[MuiltisetName.erase(MuiltisetName.find(value)) \]

来删除指定值。因为如果直接删除指定值的话,\(erase\)函数会将所有与指定值相同的元素删去,就不符合题意了。

Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100010;
const int INF = 0x3f3f3f3f;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}

int main() {
    int n = read(), k = read();
    vector<pair<int, int> > p;
    multiset<int> s;
    vector<int> h(N);
    int l = 0, max_len = 0;
    for (int r = 0; r < n; r++) {
        h[r] = read();
        s.insert(h[r]);
        while (*s.crbegin() - *s.cbegin() > k)
            s.erase(s.find(h[l++]));
        if (r - l + 1 > max_len) {
            p.clear(); //要记录最长序列长度的位置
            max_len = r - l + 1;
            p.push_back(make_pair(l + 1, r + 1));
        } else if (r - l + 1 == max_len) {
            p.push_back(make_pair(l + 1, r + 1));
        }
    }
    printf("%d %d\n", max_len, p.size());
    for (auto i : p) {
        printf("%d %d\n", i.first, i.second);
    }
    return 0;
}
posted @ 2020-09-17 19:40  Nepenthe8  阅读(97)  评论(0编辑  收藏  举报