TheBrickTowerMediumDivOne

作者:徐懿

关键词:数学 贪心

题目简述

给定一个长度为的序列

下文均用代替

对于一个的排列,定义

你需要球出一个的排列,在使得最小的情况下,的字典序尽可能小。

中元素与均为属于的整数。

约定及泉岭序列

对于一个元素不相同且均为属于的整数的序列,设中最大数的下标为的长度为。满足的重排列,。我们称为泉岭序列。

引理一

对于一个泉岭序列,有

若引理一不成立,我们可以将取出并置于,构成

这与最小矛盾,故引理一成立。

引理二

对于一个泉岭序列。设删去中代表中最大数的下标后形成为一个泉岭序列。

由引理一,中最大数下标必定在,它对的贡献恒为中最大数,与其他数独立,若要满足最小,也要最小化,故为泉岭序列。

定理一

对于一个泉岭序列,使得

时,结论显然成立。

时,由引理一,中最大数下标必定在,这与本定理相符。由引理二,在中去掉这个数后得到泉岭序列,归纳得证。

算法

我们可以由定理一,根据字典序的性质,贪心地构造出

具体地,我们以编号从小到大的顺序依次尝试,只要满足当前这个数的小于上一个数,就将其。最后将没有选入的数按数值为第一关键字递增,序号为第二关键字递增排序,置入答案排列的末尾。

具体细节参见代码。

#include <bits/stdc++.h>

std::vector<int> h,a;

bool cmp(int i,int j)//以数值为第一关键字递增,序号为第二关键字递增排序 
{
    if(h[i]!=h[j])return h[i]<h[j];
    return i<j;
}

class TheBrickTowerMediumDivOne
{
    public:
        std::vector<int> find(std::vector<int> height) 
        {
            h=height;
            a.resize(h.size());
            int j=-1;
            for(int i=0;i<h.size();i++)
            {
                if(!i || h[i]<=h[a[j]])a[++j]=i;//前缀不递增的一段 
                else a[h.size()+j-i]=i;//后缀不递减的一段(乱序) 
            }
            std::sort(a.begin()+j+1,a.end(),cmp);//将后缀排序 
            return a;
        }
};

results matching ""

    No results matching ""