题目传送门
D i l w o r t h 定理 Dilworth定理 Dilworth定理 有点意思
首先 ∣ b ∣ ≤ 4 |b|\le 4 ∣b∣≤4 ,考虑证明,证明如下:
用反证法证明
假设 ∣ b ∣ > 4 |b|>4 ∣b∣>4 , l e n len len 为 b b b 的最长不降子序列的长度.
若 l e n ≥ 3 len\ge3 len≥3 ,显然存在单调三元组,取最长不降子序列中的任意三个元素即可;
若 l e n < 3 len<3 len<3 , 则 b b b 至少由 3 3 3 个不降子序列覆盖完,根据 D i l w o r t h 定理 Dilworth定理 Dilworth定理 ,我们知道 b b b 的最长下降子序列的长度至少为 3 3 3 .
故该假设不成立,所以 ∣ b ∣ ≤ 4 |b|\le4 ∣b∣≤4 , Q E D QED QED .
关于 D i l w o r t h 定理 Dilworth定理 Dilworth定理 的证明 ,可以根据偏序关系建立有向边,形成 D A G DAG DAG ,自己尝试证明一下
接下来考虑求出以 i i i 为右端点 ,最大的左端点
先考虑 ∣ b ∣ = 3 |b|=3 ∣b∣=3 时
那么 b 2 b_2 b2 一定是 b b b 的极值,枚举 b 2 b_2 b2 , 找到最大的 b 1 b_1 b1 与 最小的 b 3 b_3 b3 ,更新 b 3 b_3 b3 的左端点
用个数据结构维护
为 O ( n log n ) O(n\log{n}) O(nlogn)的
∣ b ∣ = 4 |b|=4 ∣b∣=4 时
有 b 1 , b 4 b_1,b_4 b1,b4 一定不是极值 ,
从前往后维护 单增 和 单减 的 单调栈
对于每个位置 i i i ,找到最大的 j j j 满足 不在两个栈中,且 区间 ( j , i ) (j,i) (j,i) 可以取到两个栈的的元素
用 S e t Set Set 维护就好
为 O ( n log n ) O(n\log{n}) O(nlogn) 的
#include
using namespace std;
template void setmax(T& a, const T& b) { if (b > a) a = b; }
int N,Q;
int main() {
scanf("%d%d",&N,&Q);
vector A(N);
for (int &x:A) scanf("%d",&x);
vector> ans3(N, array({-1, -1, -1}));
vector> ans4(N, array({-1, -1, -1, -1}));
vector highs, lows;
vector inHighs(N), inLows(N);
set nonHigh,nonLow,neither;
for (int i = 0; i < N; i++) {
while (!highs.empty() && A[i] > A[highs.back()]) {
inHighs[highs.back()] = false;
nonHigh.insert(highs.back());
if (!inLows[highs.back()]) neither.insert(highs.back());
highs.pop_back();
}
while (!lows.empty() && A[i] < A[lows.back()]) {
inLows[lows.back()] = false;
nonLow.insert(lows.back());
if (!inHighs[lows.back()]) neither.insert(lows.back());
lows.pop_back();
}//maintain the monotonic stack
inHighs[i] = inLows[i] = true;
highs.push_back(i); lows.push_back(i);
auto highIt = lower_bound(highs.begin(), highs.end(), i, [&A](int x, int y) { return A[x] > A[y]; } );
auto lowIt = lower_bound(lows.begin(), lows.end(), i, [&A](int x, int y) { return A[x] < A[y]; } );
int lastHigh = highIt == highs.begin() ? -1 : *--highIt;
int lastLow = lowIt == lows.begin() ? -1 : *--lowIt;
if (!highs.empty() && !lows.empty() && !neither.empty() && *neither.begin() < min(lastHigh, lastLow)) {
auto it = neither.lower_bound(min(lastHigh, lastLow));
--it;
int bestNeither = *it;
int c = *lower_bound(highs.begin(), highs.end(), bestNeither);
int d = *lower_bound(lows.begin(), lows.end(), bestNeither);
ans4[i] = {bestNeither, min(c, d), max(c, d), i};
}
if (!highs.empty() && !nonHigh.empty() && *nonHigh.begin() < lastHigh) {
auto it = nonHigh.lower_bound(lastHigh);
--it;
int bestNonHigh = *it;
setmax(ans3[i], {bestNonHigh, *lower_bound(highs.begin(), highs.end(), bestNonHigh), i});
}
if (!lows.empty() && !nonLow.empty() && *nonLow.begin() < lastLow) {
auto it = nonLow.lower_bound(lastLow);
--it;
int bestNonLow = *it;
setmax(ans3[i], {bestNonLow, *lower_bound(lows.begin(), lows.end(), bestNonLow), i});
}
}
for (int i = 1; i < N; i++) {
ans3[i] = max(ans3[i], ans3[i-1]);
ans4[i] = max(ans4[i], ans4[i-1]);
}
for (int q = 0; q < Q; q++) {
int L, R; cin >> L >> R;
L--, R--;
if (ans4[R][0] >= L) {
puts("4");
for(int x:ans4[R]) printf("%d ",x+1);
} else if (ans3[R][0] >= L) {
puts("3");
for(int x:ans3[R]) printf("%d ",x+1);
} else {
puts("0");
}
}
}
另外,这题对代码实现能力要求也挺高的