1. 程式人生 > >JZOJ 1812. 【Usaco 2010 NOV Gold】奶牛的圖片

JZOJ 1812. 【Usaco 2010 NOV Gold】奶牛的圖片

Description

Farmer John希望給他的N(1<=N<=100,000)只奶牛拍照片,這樣他就可以向他的朋友炫耀他的奶牛.這N只奶牛被標號為1..N.
在照相的那一天,奶牛們排成了一排.其中第i個位置上是標號為c_i(1<=c_i<=N)的奶牛.對於奶牛的站位,Farmer John有他自己的想法.
FJ是這麼想的,標號為i(1<=i<=n-1)的奶牛隻能站在標號為i+1的奶牛的左邊,而標號為N的奶牛隻能站在標號為1的奶牛的左邊.當然,沒有牛可以站在佇列中最左邊的奶牛的左邊了.也就是說,最左邊的奶牛編號是隨意的.
這些奶牛都非常的餓,急切的希望吃到FJ承諾的在拍照後的大餐,所以FJ想盡快的拍照.奶牛們的方向感非常的不好,所以FJ每一分鐘只可以選擇相鄰的兩隻奶牛然後讓他們交換位置.FJ最小需要多少時間就能使奶牛站成一個可以接受的序列?
比方說一個有5只奶牛的例子,一開始序列是這樣的:
左邊 右邊
3 5 4 2 1

第一分鐘,FJ可以交換第二隊奶牛(即5和4),交換後的佇列:
3 4 5 2 1
第二分鐘,FJ交換最右邊的一對,序列變成這樣:
3 4 5 1 2
這樣,只用了2分鐘,就是序列變為了一個FJ所希望的序列.

Input

第1行:一個單獨的數N
第2到n+1行:第i+1行上的數表示站在第i的位置上的奶牛的編號(即c_i).

Output

一個整數,表示是奶牛的序列變為一個合法的序列的最小花費時間.

Sample Input

5
3
5
4
2
1

Sample Output

2

Solution

將一個凌亂的序列排成一個有序且升序的序列,我們可以想到逆序對。正解其實就是——先求這個凌亂的序列V每一個元素的位置w[i],還有序列V轉換成序列S(初始值為1-n)的步數ans。這個用樹狀陣列求。最重要的部分是把最後面的那個數i移到最前面,像“1,2,3,4,5”就移成“5,1,2,3,4”。步數的初始值x顯然是ans。中間將最後一個數i移到w[i]這個位置,這個序列稱為S1,可以求得出V到S1的距離,就是x-(n-w[i])步,然後我們還要將i移到第一位,實現將i移到最前面,所以步數x還要加上w[i]-1步。總的來說,步數x=x-(n-w[i])+w[i]-1,整理後得x=x-n+2*w[i]-1。答案則為這些x的最小值。

Code

var c,w,v:array[0..100001] of int64;
    i,j,k,l,n,m,t,s:longint;
    x,ans,min:int64;
function lowbit(x:longint):longint;
begin
    exit(x and (-x));
end;
function get(x:longint):longint;
var a:longint;
begin
    a:=0;
    while x>0 do
    begin
        inc(a,c[x]);
        x:=x-lowbit(x);
    end
; get:=a; end; procedure change(x:longint); begin while x<=n do begin inc(c[x]); x:=x+lowbit(x); end; end; begin readln(n); for i:=1 to n do begin read(v[i]); w[v[i]]:=i; end; for i:=n downto 1 do begin ans:=ans+get(v[i]); change(v[i]); end; x:=ans; min:=x; for i:=n downto 2 do begin x:=x-n+2*w[i]-1; if x<min then min:=x; end; writeln(min); end.

——2016.1.24