小朋友排隊 藍橋杯

問題描述
  n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。

  每個小朋友都有一個不高興的程度。開始的時候,所有小朋友的不高興程度都是0。

  如果某個小朋友第一次被要求交換,則他的不高興程度增加1,如果第二次要求他交換,則他的不高興程度增加2(即不高興程度爲3),依次類推。當要求某個小朋友第k次交換時,他的不高興程度增加k。

  請問,要讓所有小朋友按從低到高排隊,他們的不高興程度之和最小是多少。

  如果有兩個小朋友身高一樣,則他們誰站在誰前面是沒有關係的。
輸入格式
  輸入的第一行包含一個整數n,表示小朋友的個數。
  第二行包含 n 個整數 H1 H2 … Hn,分別表示每個小朋友的身高。
輸出格式
  輸出一行,包含一個整數,表示小朋友的不高興程度和的最小值。
樣例輸入
3
3 2 1
樣例輸出
9



解題思路:一個數最少的交換次數就是前面比它大的數+後面比它小的數;

因此我們可以藉助樹狀數組來求解前面比它大的個數,即逆序對;
求後面比它小的個數的時候我們可以倒着插入,直接統計即可;
因爲有的數據爲0,所以我們需要將所有插入的數據+1;
另外統計的時候要處理相同的數,統計前面的數的時候不用減1,統計後面的數的時候需要減1(這樣處理的原因自己思考一下便出來了);
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1000010
int n;
__int64 c[maxn+20];
int num[100010];
__int64 cnt[100010];
int lowbit(int x)
{
	return x&(-x);
} 
int updata(int x)
{
	while(x<=maxn)
	{
		c[x]+=1;
		x+=lowbit(x);
	}
}
int sum(int x)
{
	int ans=0;
	while(x>0)
	{
		ans+=c[x];
		x-=lowbit(x);
	}
	return ans;
}
int main()
{
	memset(c,0,sizeof(c));
	memset(cnt,0,sizeof(cnt));
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	scanf("%d",&num[i]);
	for(int i=0;i<n;i++)
	{
		cnt[i]+=i-sum(num[i]+1);
		updata(num[i]+1);
	}
	memset(c,0,sizeof(c));
	for(int i=n-1;i>=0;i--)
	{
		cnt[i]+=sum(num[i]);
		updata(num[i]+1);
	}
	__int64 ans=0;
	for(int i=0;i<n;i++)
	ans+=(cnt[i]*(cnt[i]+1)/2);
	printf("%I64d\n",ans);
}


發佈了125 篇原創文章 · 獲贊 23 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章