P3411 序列变换 [单调队列]
题目描述见链接 .
题目转化 为: 求数列中离散化后 最长连续不间断子序列 的长度 , .
子序列需要满足 个条件
- 编号 单调递增 .
- 子序列中的值 连续 .
- 子序列中的值 单调不减 .
可以使用 单调队列 维护 .
将所有相同的数字使用 std::vector<int>
存储其位置,
按值 从小到大 加入队列, 对于相同的值, 按位置 从大到小 加入队列 .
- 当相同值的其中一个位置可以加入队列, 比它大的位置也可以加入队列 .
若当前加入 灰色柱子, 红色柱子 的位置比 灰色柱子 大,
因此要弹掉 红色柱子, 而弹掉 红色柱子后直接加入 灰色柱子 会使得序列不满足 条件 ,
因此要弹掉所有值 小于 红色柱子 的 柱子 .
#include<bits/stdc++.h>
#define reg register
#define pb push_back
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int maxn = 1e6 + 5;
int N;
int Mx;
int Ans;
int A[maxn];
std::deque <int> Q;
std::vector <int> B[maxn];
int main(){
Ans = N = read();
for(reg int i = 1; i <= N; i ++) A[i] = read(), B[A[i]].pb(i), Mx = std::max(Mx, A[i]);
for(reg int i = 1; i <= Mx; i ++){ // 大小
int size = B[i].size();
for(reg int j = size-1; ~j; j --){
int pos = B[i][j];
while(!Q.empty() && Q.back() > pos){ // 位置
while(Q.size() >= 2 && A[Q.front()] < A[Q.back()]) Q.pop_front(); // 连续
Q.pop_back();
}
Ans = std::min(Ans, N-(int)Q.size()-(size-j));
}
for(reg int j = 0; j < size; j ++) Q.push_back(B[i][j]);
}
printf("%d\n", Ans);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步