AcWing 1215 小朋友排隊

2022-06-13 22:06:08 字數 1668 閱讀 4230

原題鏈結

考察:樹狀陣列 +貪心 or歸併排序+貪心

思路:首先乙個定理:氣泡排序的交換次數 = 逆序對個數.證明: 氣泡排序每次交換減少乙個逆序對,當最後逆序對數量 = 0,交換次數》=k. 又因為每次只能減少乙個.那麼必然可以取到k.對於某乙個人i而言,i前面>hi有k個,後面i有t個.k+t就是i的交換次數最優解,而無需考慮是否相鄰的問題.將每個人的k+t累加,和為逆序對數量*2,因為最優解的交換次數就是逆序對*2(乙個逆序對對於兩個人來說都+1).所以k+t就是i交換次數的最優解.

所以計算每個人的k+t即可,可以用歸併排序或樹狀陣列.

如果用歸併,要記錄每個人的交換前後位置差,不能用int陣列記錄第i個人交換次數,因為每人的id都在變化.

1 #include 2 #include 3 #include 4

using

namespace

std;

5 typedef long

long

ll;6

const

int n = 100010;7

intn;

8ll ans;

9struct

ssss[n],b[n];

12void merge(int l,int

r)13

24while(i<=mid) b[k++] = ss[i++];

25while(j<=r) b[k++] = ss[j++];

26for(int i=l;i<=r;i++)

2732}33

intmain()

3441 merge(1

,n);

42for(int i=1;i<=n;i++) ans +=(ll)(1+ss[i].cnt)*ss[i].cnt/2

;43 printf("

%lld\n

",ans);

44return0;

45 }

歸併樹狀陣列,記錄每個人前面》hi的有幾個,答案是summax-sumhi.樹狀陣列只能求前面<=hi的.所以可以利用字首和.

1 #include 2 #include 3 #include 4

using

namespace

std;

5 typedef long

long

ll;6

const

int n = 100010,m = 1000010;7

intn,h[n],tr[m],cnt[n];

8ll ans;

9int lowbit(int

x)10

13void add(int idx,int

x)14

17int query(int

x)18

23int

main()

2432 memset(tr,0,sizeof

tr);

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

3438

for(int i=1;i<=n;i++) ans+=(ll)cnt[i]*(cnt[i]+1)/2

;39 printf("

%lld\n

",ans);

40return0;

41 }

樹狀陣列

1215 小朋友排隊

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

acwing小朋友排隊(樹狀陣列)

考慮用樹狀陣列求解,簡單的暴力會超時。大概思路 每個數會和前面比它大的數交換,會和後面比它小的數交換,所以每個數交換的總次數為前面比這個數大的數的個數 後面比這個數小的個數,下面的 用b i 維護這個個數和。如何求呢?用樹狀陣列儲存每個數出現的次數。第一次正向遍歷,每次將資料出現的次數加入到樹狀陣列...

小朋友排隊

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