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