藍橋杯 歷屆試題 小朋友排隊

2021-08-15 15:22:09 字數 3450 閱讀 3108

歷屆試題 小朋友排隊  

時間限制:1.0s   記憶體限制:256.0mb

問題描述

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。

在這一題裡我也卡了一段時間

一開始我單純的一位是排序題採用氣泡排序解決

然後寫了一套排序解決方案

然後樣例資料通過後進行提交發現只通過了前三個資料

並且6-10題都是執行超時

後來查詢網上一些其他大神的資料發現氣泡排序在這一題裡並不能有不開心數的最小值

而且因為排序需要遍歷兩次在題目要求中的1000000這麼大的資料裡迴圈兩次必然會執行超時

後來查詢資料得知這一題不開心值的解決方案最小值求法是找逆序對

使用樣例資料中的例子來打比方

輸入資料是 3 2 1

要從小到大排列則3至少要交換兩次【因為3後面有兩個數比它小,即3與2 必然交換一次,3與1也必然交換一次】

要排列2也至少交換兩次【因為2前面有乙個數3比它大,後面有乙個數1比它小】

排列1也是至少交換兩次【因為1前面有兩個數比它大】

以此類推,可以得知每乙個數要交換的次數為這個數前面比它大的數+後面比它小的數,即逆序對數

知道這乙個規律後使用for迴圈也可以求出這些值,但是至少也需要兩輪for迴圈來遍歷每乙個數

在題目的最大資料規模裡,必然會執行超時

因此不能使用for迴圈遍歷每個數來求最小交換次數

後來看別人的解法還有查詢資料得知有一種快速求前面所有數的和的方法叫做樹狀陣列

樹狀陣列具體理解可以看這一篇大神的博文

我這裡不詳細講解樹狀陣列的實現等,只講解解法和功效

樹狀陣列常用於區間查詢任意兩位元素之間所有元素之和

在此題中可以採用這種方法快速求逆序對

首先用這種方法儲存所錄入的身高資料

設正在錄入的身高為x,然後將c[x+1]=c[x+1]+1(陣列c的初始值為0,這一種儲存方法可以想象為這一群不同身高的學生,老師叫他們按照身高站,身高為x的學生統一站到x+1群裡,則有幾個身高為x的學生,c[x]就等於幾.)【為什麼要x+1?因為樹狀陣列操作空間是1~正無窮,而題目中可能的身高值裡有0】

用這種方法儲存身高,只要得知c[1]~c[x+1]的和,就能知道前面有多少人比自己矮【雖然這個是順序的,我們需要獲得的是逆序對,但是獲取到這個資料也是有用的】

要知道前面有多少人比自己高則可以這樣子求,已經錄入的資料值-當前身高的值的人數-比當前身高矮的人數【比如總共需要錄入n個資料,現在在錄第i個資料,身高為x,則n-i-c[x+1]就是比自己高的人數】,即已經錄入的人數減去比自己高的和自己一樣高的人的人數,剩餘的人數就是比自己矮的。

然後需要的資料為後面錄入的人裡比自己矮的人數,這個可以採用一樣的方法,先重置c陣列,然後逆序進行重新錄入。【此處重新錄入是需要把第一次錄入的值儲存下來,即一開始輸入資料為3 2 1 ,逆序錄入時錄入 1 2 3 】,然後在此時需要的是獲取到比自己矮的人數,當前錄入身高為x,想知道多少比自己矮可以直接獲取c[1]~c[x+1]的和。

具體**如下

#include#includeusing namespace std;

//a為原陣列,b為按大小排序的陣列,c為b的樹狀陣列,d為暫存的不開心值 ,e為等差數列儲存不高興值的遞增值

int a[100001],b[1000003],c[1000003],d[1000003];

long long int e[100002];

//位運算

int lowbit(int x)

//定義修改c陣列的函式,第乙個值代表陣列位置,第二個代表陣列值,在此題中只需預設加一

void update(int local,int num)

}//查詢前多少區間的和

int read(int i)

return sum;

}//清零函式

void ini()

int main()

ini();

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

e[1]=1;

for(i=2;i裡面需要注意的是一些地方因為資料過大超過了int 儲存範圍

第一處是總不開心值sum,這裡不採用long long int的話可能會超出資料範圍導致無法通過樣例資料【這裡的報錯包括下面的那個沒有用long long int 的錯誤】

另一處需要用long long int的地方是

long long int e[100002];

這裡引起的報錯是

這個陣列是我用來儲存不開心值的等差數列,即當小朋友交換一次時不開心值為1則e[1]=1,交換兩次不開心值為1+2即e[2]=e[1]+2=3,雖然可以使用等差數列求和公式來快速獲取最後值,但是考慮到交換次數可能重複,所以採用陣列儲存具體值,避免計算使用消耗記憶體。【雖然好像因為裡面有很多多餘的計算也消耗了很多記憶體。。。】

總結經驗是對於大規模資料運算,對於不確定資料規模會不會過大時要記得用long long int,不然找bug找半天

其實經驗是學習快速區間求值的方法是樹狀陣列

藍橋杯 歷屆試題 小朋友排隊

時間限制 1sec 記憶體限制 128mb 提交 75 解決 11 題目描述 n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。每個小朋友都有乙個不高興的程度。開始的時候,所有小朋友的不高興程度都是0。如果某個小朋友第一次被要求交換,則他的不高興程度增...

藍橋杯 歷屆試題 小朋友排隊 C

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

藍橋 歷屆試題 小朋友排隊

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