日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【蓝桥杯官网试题 - 历届试题】小朋友排队(逆序数,树状数组)

發布時間:2023/12/10 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【蓝桥杯官网试题 - 历届试题】小朋友排队(逆序数,树状数组) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題干:

問題描述

  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。

解題報告:

我就說嘛、、、過了70%,不可能是思路錯誤,,檢查了半天發現最后的統計答案爆了longlong、、、氣死我了。

這題的關鍵在于看到交換的條件是:只能交換相鄰的兩個元素。這就使得問題簡單了很多。考慮到x這個數,假設最后肯定要被交換到對應的位置上,那么看最少需要被交換多少次,在看這個次數能否可以實現。不難發現,最少被交換的次數,就是和前面比他大的數字,并且和后面比他小的數字。所以求該數對應的逆序數就行了。那么這個次數能否實現呢?不妨這樣想,只考慮第i個數,假設前面比他大的有x1個,后面比他小的有x2個,我們先想辦法將他前面比他大的數都交換到他后面去,這樣他移動的次數就肯定是x1,并且得到的這樣一個狀態肯定是在他本該在的位置的前面,然后我們再通過和后面的數字的交換讓他回到原來的位置就可以了,這一套操作是x2次,所以總次數可以達到x1+x2次。

AC代碼:

#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 2e6 + 5; int a[MAX]; int c[MAX]; int lowbit(int x){return x&(-x);} int query(int x) {int res = 0;while(x>0) {res += c[x];x-=lowbit(x);}return res; } void update(int x,int val) {while(x<MAX) {c[x] += val;x+=lowbit(x);} } int ans1[MAX],ans2[MAX],ans[MAX]; int main() {int n;cin>>n;for(int i = 1; i<=n; i++) {scanf("%d",a+i);a[i]++;}for(int i = n; i>=1; i--) {ans1[i] = query(a[i]-1);update(a[i],1);}memset(c,0,sizeof c);for(int i = 1; i<=n; i++) {ans2[i] = query(1000010) - query(a[i]);update(a[i],1);}for(int i = 1; i<=n; i++) ans[i] = ans1[i] + ans2[i];ll res = 0;for(int i = 1; i<=n; i++) {res += 1LL*(1+ans[i])*ans[i]/2;}printf("%lld\n",res);return 0 ; }

?

總結

以上是生活随笔為你收集整理的【蓝桥杯官网试题 - 历届试题】小朋友排队(逆序数,树状数组)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。