1. 程式人生 > >[USACO10NOV]奶牛的圖片Cow Photographs

[USACO10NOV]奶牛的圖片Cow Photographs

set 最小 farmer target cout lan sdi open tom

題目描述

Farmer John希望給他的N(1<=N<=100,000)只奶牛拍照片,這樣他就可以向他的朋友炫耀他的奶牛.

這N只奶牛被標號為1..N. 在照相的那一天,奶牛們排成了一排.其中第i個位置上是標號為 ci(1<=ci<=N)c_i(1<=c_i<=N)ci?(1<=ci?<=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所希望的序列.

輸入輸出格式

輸入格式:

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

輸出格式:

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

輸入輸出樣例

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

提交地址:Luogu4545

眾多USACO搜索題中的一股小清流;
剛看題:裸的逆序對渺
笑容逐漸凝固:woc這沒我想的那麽簡單...

我們的逆序對可以解決從1~n的排列問題, 但是這道題顯然不是從1~n的排列;
那怎麽辦呢?
例如234561的序列, 逆序對個數為5, 這表明我們要換5次,是嗎?顯然不是, 我們一次都不用換;
那我們該怎樣考慮這個問題呢?
我們可以把1想象成7!這樣逆序對為0,且滿足題意;
再舉個例子, 3456721;
原始逆序對為10個;我們把1想象成8, 逆序對為5;
我們把2想象成9,逆序對為1;

意思是,我們從小到大枚舉一個數假設它最大, 意思是它就是序列的一個結尾;
那我們怎樣快速地求出修改之後的逆序對的數量呢?
顯然最小的數產生的逆序對數量等於pos[i]-1, 就是它位置減一;
它成為最大值之後會增加n-pos[i]個新的逆序對;
所以我們可以先求出原先序列的逆序對, 然後枚舉最小的數為最大數, 修改逆序對的數量, 然後取min;
代碼奉上:
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 inline int read()
 7 {
 8     int res=0;bool fl=0;char ch=getchar();
 9     while(!isdigit(ch)){if(ch==-)fl=1;ch=getchar();
10     }while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch-0);ch=getchar();
11     }return fl?-res:res;
12 }
13 
14 int n;
15 int a[100010];
16 int pos[100010];
17 
18 int t[1000010];
19 inline int lowbit(int x){return x & -x;}
20 
21 inline void add(int x, int y){while(x <= n){t[x]+=y;x+=lowbit(x);}}
22 
23 inline int query(int x){int ans=0;while(x!=0)ans+=t[x], x-=lowbit(x);return ans;}
24 
25 long long ans;
26 long long best;
27 
28 int main()
29 {
30     n = read();
31     for (register int i = 1 ; i <= n ; i ++) a[i] = read(), pos[a[i]] = i;
32     
33     for (register int i = n ; i >= 1 ; i --)
34     {
35         ans += query(a[i] - 1);
36         add(a[i], 1);
37     }
38     
39     best = ans;
40     
41     for (register int i = 1 ; i <= n ; i ++)
42     {
43         best = best - (pos[i] - 1) + (n - pos[i]);
44         ans = min(ans, best);
45     }
46     cout << ans << endl;
47     return 0;
48 }

 

[USACO10NOV]奶牛的圖片Cow Photographs