歷屆試題 小朋友排隊【樹狀陣列】
阿新 • • 發佈:2018-12-11
歷屆試題 小朋友排隊
時間限制: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。
思路:
這一題主要是求每個人被交換的次數,最後用自然數求和公式即可。
我們可以發現一個人被交換的次數=前面大於它的人的個數+後面小於它的人的個數。
這樣就轉化為類似於求逆序數了。
模擬插入排序可以過90%,用樹狀陣列可以過100%,注意相等的情況。
程式碼:
#include<bits/stdc++.h> using namespace std; #define MAXN 100005 #define ll long long int n,t[MAXN],c[MAXN],dis[MAXN]; struct node { int x,i; } p[MAXN]; bool cmp(node a,node b) { return a.x < b.x; } int lowbit(int i) { return i&(-i); } void add(int i,int x) { while(i<=n) { c[i]+=x; i+=lowbit(i); } } int sum(int i) { int res=0; while(i) { res+=c[i]; i-=lowbit(i); } return res; } int main() { scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%d",&p[i].x); p[i].i=i; } memset(dis,0,sizeof dis); sort(p+1,p+n+1,cmp); for(int i=1; i<=n; i++) { t[p[i].i]=i; if(i>1 && p[i].x==p[i-1].x) t[p[i].i]=t[p[i-1].i]; } long long ans=0; memset(c,0,sizeof c); for(int i=1; i<=n; i++) { add(t[i],1); ll s=i-sum(t[i]); dis[t[i]]++; s+=t[i]-sum(t[i])+dis[t[i]]-1; ans+=(1+s)*s/2; } printf("%lld\n",ans); return 0; }