小朋友排隊 藍橋杯

2021-08-17 13:12:48 字數 3274 閱讀 8525

問題描述

n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。

每個小朋友都有乙個不高興的程度。開始的時候,所有小朋友的不高興程度都是0。

如果某個小朋友第一次被要求交換,則他的不高興程度增加1,如果第二次要求他交換,則他的不高興程度增加2(即不高興程度為3),依次類推。當要求某個小朋友第k次交換時,他的不高興程度增加k。

請問,要讓所有小朋友按從低到高排隊,他們的不高興程度之和最小是多少。

如果有兩個小朋友身高一樣,則他們誰站在誰前面是沒有關係的。

輸入格式

輸入的第一行包含乙個整數n,表示小朋友的個數。

第二行包含 n 個整數 h1 h2 … hn,分別表示每個小朋友的身高。

輸出格式

輸出一行,包含乙個整數,表示小朋友的不高興程度和的最小值。

樣例輸入3

3 2 1

樣例輸出

9樣例說明

首先交換身高為3和2的小朋友,再交換身高為3和1的小朋友,再交換身高為2和1的小朋友,每個小朋友的不高興程度都是3,總和為9。

資料規模和約定

對於10%的資料, 1<=n<=10;

對於30%的資料, 1<=n<=1000;

對於50%的資料, 1<=n<=10000;

對於100%的資料,1<=n<=100000,0<=hi<=1000000。

問題的關鍵在於查詢逆序對的個數,最容易想到的當然就是暴力**,看看資料範圍,超時無疑,於是我們就需要使用乙個特殊的陣列----樹狀陣列。

首先我們看看樹狀陣列的特點,當然就是很快速的求前n個元素的和,那這和我們求逆序對有什麼關係呢?

這裡,我們要巧妙地變一下形,還是以題目中給出的資料為例 3   2   1

因為樹狀陣列實際上是由兩部分組成:資料陣列+統計陣列,我們只看資料陣列

由於樹狀陣列是從1開始的,而題目中小盆友的身高可以為0(真是長見識了),所以我們將每個小盆友的身高加1然後作為樹狀陣列的下標,將數值1存到相應的位置.

第一次讀入3,此時讀入的資料量為1個,變成這樣

c[1]        c[2]        c[3]        c[4]       c[5]        c[6]         c[7]         c[8]

0             0            0            1            0             0             0              0

可以看到sum(c[1],c[4])=1(可以由樹狀陣列的統計陣列得到),這個是小於等於3的數字的個數,也就是說當輸入第乙個數字3的時候沒有比它小的數字存在,這時我們用 輸入數字總數-sum(c[1],c[4])=0,也就是說大於3的數字的個數為0,我們令b[0]=0.

第二次讀入2,此時讀入的資料量為2個,變成這樣

c[1]        c[2]        c[3]        c[4]       c[5]        c[6]         c[7]         c[8]

0             0            1            1            0             0             0              0

可以看到sum(c[1],c[3])=1,任然不存在比它小的數,但此時輸入的資料總量為2,而2-1=1,就是說,存在乙個數在2之前並且大於2,這個數當然就是3,我們另b[1]=1.

第三次讀入1,此時讀入的資料量為3,變成這樣

c[1]        c[2]        c[3]        c[4]       c[5]        c[6]         c[7]         c[8]

0             1            1            1            0             0             0              0

可以看到sum(c[1],c[2])=1,任然不存在比它小的數,但此時輸入的資料總量為3,而3-1=2,就是說,存在兩個數在1之前並且大於1,這個數當然就是2,3,我們另b[2]=2.

到此,我們已經算出了每個數前面的較大的數的個數了,資料存在num中,現在我們再反過來,先插入1,再插入2,再插入3,但這次我們不再用總數減去sum了,而直接求sum,求出來的自然就是,每個數後面的較小的數的個數,然後將得到的數值累加到相應的b[i]中,最終我們會得到b[0]=2,b[1]=2,b[2]=2,分別對應num[0]=3,num[1]=2,num[2]=1。

求得了每個小盆友被移動的次數,我們需要計算其不高興程度,這裡實際上可以事先打個表,就是將被移動n次後的不高興值全算出來,然後直接用就可以了,這裡,我們將其存到total陣列中,而且total[2]=3,所以總不高興值就是9.

需要注意的是如果重複的數字出現怎麼辦,如果出現,實際上出問題的會是求每個數之前較大數的那部分,因為用到了數的總個數,如果出現一樣的數,就會導致相減後的結果偏大,而且正好是大了 重複量-1 ,那麼我們就可以算出重複量,然後將這一部分減去就行,關鍵是怎麼算重複量,實際也很簡單,通過樹狀陣列,我們可以求得sum(1,a)和sum(1,a+1),其中輸入的數字為a,前者算出的小於a的數的個數,後者算出的是小於等於a的數的個數,兩個一減就是等於a的個數。

#include#include#includeusing namespace std;

#define size 1000000+10

#define n 100000+10

int height[size];//記錄每個身高

int c[size];//這是樹狀陣列的統計陣列

long long b[n];//記錄每個人的前逆序對+後逆序對

int n;

long long judge[n];//不高興度錶judge[i]代表移動n次的不高興度

int lowbit(int x)

void add(int pos,int num)

return re;

}void fun()

memset(c,0,sizeof(c));

for(int i=n-1; i>=0; i--)

long long ans=0;

for(int i=0;i>n;

memset(height,0,sizeof(height));//初始化

memset(c,0,sizeof(c));

memset(b,0,sizeof(b));

judge[0]=0;

for(i=1; ifun();

return 0;

}

小朋友排隊 藍橋杯

因此我們可以借助樹狀陣列來求解前面比它大的個數,即逆序對 求後面比它小的個數的時候我們可以倒著插入,直接統計即可 因為有的資料為0,所以我們需要將所有插入的資料 1 另外統計的時候要處理相同的數,統計前面的數的時候不用減1,統計後面的數的時候需要減1 這樣處理的原因自己思考一下便出來了 includ...

藍橋杯 小朋友排隊

歷屆試題 小朋友排隊 時間限制 1.0s 記憶體限制 256.0mb 問題描述 n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。每個小朋友都有乙個不高興的程度。開始的時候,所有小朋友的不高興程度都是0。如果某個小朋友第一次被要求交換,則他的不高興程度...

藍橋杯 小朋友排隊

n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。每個小朋友都有乙個不高興的程度。開始的時候,所有小朋友的不高興程度都是0。如果某個小朋友第一次被要求交換,則他的不高興程度增加1,如果第二次要求他交換,則他的不高興程度增加2 即不高興程度為3 依次類推...