目前不會!!
n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。每個小朋友都有乙個不高興的程度。開始的時候,所有小朋友的不高興程度都是0。如果某個小朋友第一次被要求交換,則他的不高興程度增加1,如果第二次要求他交換,則他的不高興程度增加2(即不高興程度為3),依次類推。當要求某個小朋友第k次交換時,他的不高興程度增加k。請問,要讓所有小朋友按從低到高排隊,他們的不高興程度之和最小是多少。如果有兩個小朋友身高一樣,則他們誰站在誰前面是沒有關係的。
【資料格式】
輸入的第一行包含乙個整數n,表示小朋友的個數。
第二行包含 n 個整數 h1 h2 … hn,分別表示每個小朋友的身高。
輸出一行,包含乙個整數,表示小朋友的不高興程度和的最小值。
【資料規模與約定】
對於10%的資料, 1<=n<=10;
對於30%的資料, 1<=n<=1000;
對於50%的資料, 1<=n<=10000;
對於100%的資料,1<=n<=100000,0<=hi<=1000000。
例如,輸入:
33 2 1
程式應該輸出:
9
題目分析:
這是一道尋找逆序數的題目,比如題目中的3,2,1,和3有關的逆序對為3,2和3,1,和2有關的逆序對為3,2和2,1,和1有關的逆序對為3,1和2,1,為了完成排序,任何乙個逆序對的兩個元素都必須交換一次,於是可知,每個小朋友都完成了兩次交換。
說白了就是針對每乙個元素,看看它之前有幾個大於它的元素,之後有幾個小於它的元素,然後記錄這個元素在逆序對中出現的次數,也就是含這個元素的逆序對的個數,然後再將每個元素的不高興程度相加即可。問題的關鍵在於查詢逆序對的個數,最容易想到的當然就是暴力**,看看資料範圍,超時無疑,於是我們就需要使用乙個特殊的陣列----樹狀陣列。
樹狀陣列的特點就是很快速的求前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#define max 1000010
#define n 100010
using namespace std;
int c1[max],c2[max],b[max];
int num[n];
long long total[n],ans;
int lowbit(int x)
void add(int pos,int num,int *c)
}int sum(int pos,int *c)
return sum;
}void init()
}int main()
//for(int j=0;j<20;j++)
// cout/ cout
for(i=0;icout
}
小朋友排隊 第五屆藍橋杯
第一種,直接思考的方法,不知對不正確 n 個小朋友站成一排。如今要把他們按身高從低到高的順序排列,可是每次僅僅能交換位置相鄰的兩個小朋友。每乙個小朋友都有乙個不高興的程度。開始的時候。全部小朋友的不高興程度都是0。假設某個小朋友第一次被要求交換,則他的不高興程度新增1,假設第二次要求他交換。則他的不...
小朋友排隊 第五屆藍橋杯b組
氣泡排序 要交換的次數等於序列中逆序對的個數。設逆序對數量k,所以交換次數至少是k。每一次交換後逆序對數量必然減一。所以總數最小是k。include include include includeusing namespace std typedef long long ll const int n...
小朋友排隊
n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。每個小朋友都有乙個不高興的程度。開始的時候,所有小朋友的不高興程度都是0。如果某個小朋友第一次被要求交換,則他的不高興程度增加1,如果第二次要求他交換,則他的不高興程度增加2 即不高興程度為3 依次類推...