P3411 序列变换 [单调队列]

序列变换

题目描述见链接 .


color{red}{正解部分}

题目转化 为: 求数列中离散化后 最长连续不间断子序列 的长度 lenlen, ans=Nlenans = N-len .

子序列需要满足 33 个条件 downarrow

  • 编号 单调递增 .
  • 子序列中的值 连续 .
  • 子序列中的值 单调不减 .

可以使用 单调队列 维护 .


color{red}{实现部分}

将所有相同的数字使用 std::vector<int> 存储其位置,

按值 从小到大 加入队列, 对于相同的值, 按位置 从大到小 加入队列 .


  • 当相同值的其中一个位置可以加入队列, 比它大的位置也可以加入队列 .

若当前加入 灰色柱子, 红色柱子 的位置比 灰色柱子 大,
因此要弹掉 红色柱子, 而弹掉 红色柱子后直接加入 灰色柱子 会使得序列不满足 条件 22,
因此要弹掉所有值 小于 红色柱子 的 柱子 .

#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
", Ans);
        return 0;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822424.html