BZOJ2457 双端队列 题解

本题直接求解十分困难,因为在不知道整个序列的数字规律时当前所作决策都无法保证最优性。
考虑正难则反,题目转化为将一个非降序列分成尽量少的几段,让每段对应原问题的双端队列。
先将原数组排序,由于原数组下标对应了插入的顺序,那么根据双端队列的性质,被划分出的每一段的下标都应该满足单谷性质(最先插入的在最中间,之后向两边递增)。
又发现由于是非降序列,那么相同数字的次序不是固定的,可以通过交换两个相同数字使答案更优。
所以此题做法为:对数字相同的每一段依次考虑,利用贪心策略把当前序列(下标)递减或递增地插入序列末尾。

#include <cstdio>
#include <algorithm>
using namespace std;

struct P{int v,od;}a[200005];
int n,ans=1;

bool cmp(P x,P y) {return x.v==y.v?x.od<y.od:x.v<y.v;}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        scanf("%d",&a[i].v),a[i].od=i;
    sort(a+1,a+n+1,cmp);
    bool fl=0; int last=n+2;
    for(int i=1,j=1;i<=n;i=++j)
    {
        while(j<=n&&a[j+1].v==a[j].v) ++j;
        if(fl)
        {
            if(a[i].od>last) last=a[j].od;
            else ++ans,fl=0,last=a[i].od;
        }
        else
        {
            if(a[j].od<last) last=a[i].od;
            else fl=1,last=a[j].od;
        }
    }
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/wzzyr24/p/12003051.html