1. 程式人生 > >HihoCoder - 1886 :中位數2(貪心)

HihoCoder - 1886 :中位數2(貪心)

描述

對於一個長度為n的數列A,我們如下定義A的中位數med(A):

當n是奇數時,A的中位數是第(n+1)/2大的數;當n是偶數時,A的中位數是第n/2大的數和第n/2+1大的數的平均值。  

同時,我們如下定義A的字首中位數和:

S(A) = med(B1) + med(B2) + med(B3) + ... + med(Bn)

其中Bi是A長度為i的字首,即Bi=(A1, A2, A3 ... Ai-1, Ai),1 ≤ i ≤ n。  

現在給定一個長度為n的數列X,我們希望通過將X中的數重新排列得到數列Y,使得S(Y)最大。

例如對於X=(2, 3, 1, 5, 4),將X重新排列成Y=(5, 4, 3, 2, 1)會使得S(Y)最大,為5 + 4.5 + 4 + 3.5 + 3 = 20。

為了描述方便,我們用一個1-n的排列P來表示重排的方法,即P滿足XPi = Yi, 1 ≤ i ≤ n。例如在上面將X變成Y的重排中,P=(4, 5, 2, 1, 3)。

你能找到使S(Y)最大重排方案P嗎? 如果有多個P滿足條件,輸出字典序最小的P。

對於兩個長度為n排列P和Q,我們稱P字典序小於Q當且僅當存在k滿足

1. 1 ≤ k ≤ n 且

2. 對於任意i ≤ k,有Pi=Qi,且

3. Pk < Qk

輸入

第一行包含一個整數n (1 ≤ n ≤ 100000)  

第二行包含n個整數,分別是X1, X2, ... Xn (1 ≤ Xi ≤ n)

輸出

一行包含n個整數代表字典序最小的P

樣例輸入
5
1 2 3 4 5
樣例輸出
5 4 1 3 2

 

思路:大的數如果後放,是很難作為中位數的,所以大的數應當靠前放。 而在放了幾個足夠大的數後,我們考慮可以在中位數不變的情況下,從左到右放幾個數,從而保證結果最大,而字典序最小。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int
maxn=1000010; struct in{ int x,pos; }s[maxn]; bool cmp(in w,in v){ return w.x==v.x?w.pos<v.pos:w.x>v.x; } int ans[maxn],used[maxn],pos; int main() { int N; scanf("%d",&N); rep(i,1,N) scanf("%d",&s[i].x),s[i].pos=i; sort(s+1,s+N+1,cmp); pos=1; rep(i,1,N){ if(used[s[i/2+1].pos]) { while(used[pos]) pos++; ans[i]=pos; used[pos]=1; } else ans[i]=s[i/2+1].pos,used[s[i/2+1].pos]=1; } rep(i,1,N) printf("%d ",ans[i]); return 0; }