原題鏈結
考察:樹狀陣列 +貪心 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歸併樹狀陣列,記錄每個人前面》hi的有幾個,答案是summax-sumhi.樹狀陣列只能求前面<=hi的.所以可以利用字首和.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 }
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 依次類推...