1. 程式人生 > >Bzoj 2058: [Usaco2010 Nov]Cow Photographs 題解

Bzoj 2058: [Usaco2010 Nov]Cow Photographs 題解

none mit pre col 希望 有趣 沒有 aps geo

2058: [Usaco2010 Nov]Cow Photographs

Time Limit: 3 Sec Memory Limit: 64 MB
Submit: 190 Solved: 104
[Submit][Status][Discuss]

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
  這道題挺有趣的,他更多的是對我們能否看透題目本質的考察。   首先,我們可以先明確一點,對於一個已知序列,如果我們要把它調為123……那麽我們需要移動的步數就是這個序列的逆序對數。   讓我們觀察一下樣例最終的答案: 34512,我們會發現1左側是單調遞增,1及其右側也是單調遞增,只是在1這裏斷開了而已。如果我們測試一下其他我們自己造出來的小數據我們可以發現同樣的規律。那我們難道要把整個序列拆開來看嗎?不必,我之前說了只是在上升序列只是1這裏斷開了而已,那我們為什麽不能直接將1,2轉化為6,7呢?顯然,這樣是正確且方便的。對於新的答案,我們也不必再去O(nlogn)查詢。我們對於答案作出的改變就是這個數改變後的貢獻-這個數之前的貢獻。由於這個數之前是最小的數,所以他之前的貢獻就是他的now-1,由於他改變後是最大的數,所以改變後的貢獻就是n-now。
技術分享
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <queue>
 6 #include <algorithm>
 7 #include <cmath>
 8 #include <map>
 9 #include <set>
10 #define N 100005
11 using namespace std;
12 int n,a[N],b[N],dl[2
*N]; 13 int lowbit(int x) 14 { 15 return x&(-x); 16 } 17 void add(int x) 18 { 19 for(int i=x;i<=n;i+=lowbit(i)) 20 b[i]++; 21 } 22 int get(int x) 23 { 24 int ans=0; 25 for(int i=x;i>0;i-=lowbit(i)) 26 ans+=b[i]; 27 return ans; 28 } 29 long long ans[N]; 30 int main() 31 { 32 scanf("%d",&n); 33 for(int i=1;i<=n;i++) scanf("%d",&a[i]),dl[a[i]]=i; 34 for(int i=n;i>=1;i--) 35 { 36 ans[0]+=get(a[i]); 37 add(a[i]); 38 } 39 long long mn=ans[0]; 40 for(int i=1;i<n;i++) 41 { 42 a[dl[i]]=n+i-1; 43 ans[i]=ans[i-1]-(dl[i]-1)+n-dl[i]; 44 mn=min(mn,ans[i]); 45 dl[n+i-1]=i; 46 } 47 printf("%lld\n",mn); 48 return 0; 49 }
View Code

Bzoj 2058: [Usaco2010 Nov]Cow Photographs 題解