CodeForces - 6E Exposition(尺取法+multiset)
阿新 • • 發佈:2020-09-17
題目大意:
給一個\(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; }