小朋友排队|2014年蓝桥杯B组题解析第十题-fishers
小朋友排隊
n 個小朋友站成一排?,F在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。
每個小朋友都有一個不高興的程度。開始的時候,所有小朋友的不高興程度都是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。
資源約定: 峰值內存消耗 < 256M CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。
所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。
注意: main函數需要返回0 注意: 只使用ANSI C/ANSI C++ 標準,不要調用依賴于編譯環境或操作系統的特殊函數。 注意: 所有依賴的函數必須明確地在源文件中 #include , 不能通過工程設置而省略常用頭文件。
提交時,注意選擇所期望的編譯器類型。
思路一:求逆序對:左邊大于它的 + 右邊小于它的數量,求完逆序對后,計算等差數列和 (因為不高興程度每次增加k)
待改進:只能過50%的數據,超時了。需要用歸并排序 和 樹狀數組改進。
#include<iostream> using namespace std;int n; int arr[1000010]; long long ans = 0;/* 求逆序對:左邊大于它的 + 右邊小于它的數量 求完逆序對后,計算等差數列和 (因為不高興程度每次增加k) */ long long cal(long long x){return x + x*(x-1)/2; }int main(){cin>>n;for(int i=1;i<=n;i++){cin>>arr[i];}for(int i=1;i<=n;i++){long long ans1 = 0;long long ans2 = 0;for(int j=1;j<i;j++){if(arr[j] > arr[i]){ans1++;}}for(int j=i+1;j<=n;j++){if(arr[j]<arr[i]){ans2++;}}ans+=cal(ans1 + ans2); }cout<<ans<<endl; }思路二:使用樹狀數組優化,求逆序對
????先熟悉樹狀數組原理及其應用。
? ? 1.這道題可以轉換成求每個位置的左邊比他小的個數和右邊比他大的個數,這兩個相加就是這個人要被交換的次數,然后根據等差數列前n項求和公式(a1+an)*n/2,將所有位置和相加即可。
????2.求逆序數用樹狀數組優化成 nlogm,樹狀數組是專門用來求前綴和的,這里從位置0遍歷到n-1,把高度作為樹狀數組的下標,每個高度對應的個數作為樹狀數組的值,對于輸入的小朋友高度a[i],在當前小朋友左邊&&比當前小朋友a[i]高的總數,就是樹狀數組s(maxh)-s(a[i])=i+1-s(a[i]),反之同理。
注意事項:
????1.題中a[i]可以等于0,所以要把輸入加一,不然在后面計算sum(a[i]-1)處,會越界。
????2.代碼中a數組是保存輸入,d數組的下標是高度,lr數組是保存位置i的左右逆序總數,maxh是輸入的最大值
代碼:
#include <iostream> #include <cstdio> #define _for(i,a,b) for(int i=a;i<b;i++) #define _unfor(i,a,b) for(int i=a;i>=b;i--) #define mset(a,val,n) for(int i=0;i<n;i++)a[i]=val; #define lowbit(x) (x&(-x)) using namespace std; typedef long long LL;int a[100005],d[1000005],n,lr[100005],maxh=0; //tree_arrvoid add(int i,int x){while(i<=maxh+1)d[i]+=x,i+=lowbit(i);}int sum(int i){int res=0;while(i>0)res+=d[i],i-=lowbit(i);return res;} // int main(){scanf("%d",&n);_for(i,0,n){scanf("%d",&a[i]);maxh=max(maxh,++a[i]);}_for(i,0,n){add(a[i],1);lr[i]+=i+1-sum(a[i]);}mset(d,0,maxh+5);_unfor(i,n-1,0){add(a[i],1);lr[i]+=sum(a[i]-1);}LL ans=0;_for(i,0,n){LL k=lr[i];ans+=k*(k+1)/2;}cout<<ans<<endl; }轉載于:https://www.cnblogs.com/fisherss/p/10286608.html
總結
以上是生活随笔為你收集整理的小朋友排队|2014年蓝桥杯B组题解析第十题-fishers的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mongose + express 写R
- 下一篇: meta标签的用处详解