2014年第五届蓝桥杯C++省赛B组J题

2014年第五届蓝桥杯C++省赛B组J题

小朋友排队

n 个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。

每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。

如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。

请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。

如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。

【数据格式】

输入的第一行包含一个整数n,表示小朋友的个数。
第二行包含 n 个整数 H1 H2 … Hn,分别表示每个小朋友的身高。
输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。
例如,输入:
3
3 2 1
程序应该输出:
9

【样例说明】
首先交换身高为32的小朋友,再交换身高为31的小朋友,再交换身高为21的小朋友,每个小朋友的不高兴程度都是3,总和为9

【数据规模与约定】
对于10%的数据, 1<=n<=10;
对于30%的数据, 1<=n<=1000;
对于50%的数据, 1<=n<=10000;
对于100%的数据,1<=n<=100000,0<=Hi<=1000000。

典型树状数组的运用~喵
暴力的话,n到1e4,要平方,就是1e8,可能就不行了。。
所以还是树状数组把=-=

说好的今天写树形dp的。。呃。。。
先把这个题目写完把=-=
这个地方c[]数组维护的是小朋友身高的个数。
把小朋友的身高对应为c[]的下标。因为身高可以为0,最高可以达到1e6。。。(这些小朋友好厉害。。。),树状数组一般不用0下标,所以身高普遍+1了。
所以getsum()获取的是比当前小朋友身高矮的小朋友个数
我们需要计算一个小朋友左边比他高的小朋友个数,和右边比他矮的小朋友个数。然后跟新当前小朋友的交换次数。最后等差数列求和可以得到这个小朋友的怒气值。
最后维护一下ans就可以啦

计算一个小朋友左边比他高的。就是顺序求即可。拿当前计数到多少个小朋友减去sum()值
计算一个小朋友右边比他矮的。就是逆序求。这个之前需要mst一下c[]数组。计算比他矮的就可以了。注意存在身高一样的小朋友

所以。。上代码啦~

#include <bits/stdc++.h>
#define mst(a, n) memset(a, n, sizeof(a))
#define lowbit(x) ((x) & -(x))
const int N = 1e6 + 10;
using namespace std;
typedef long long ll;

int n;
int h[N];
int c[N];
ll cnt[N];
ll ans;

void update(int n, int i, int v)
{
	for (int k = i; k <= n; k += lowbit(k))
	{
		c[k] += v;
	}
}

int getSum(int i)
{
	int sum = 0;
	for (int k = i; k >= 1; k -= lowbit(k))
	{
		sum += c[k];
	}
	return sum;
}

int main()
{
	cin >> n;
	int maxx = -1;
	for (int i = 0; i < n; i++)
	{
		scanf ("%d", &h[i]);
		if (maxx < h[i])
		{
			maxx = h[i];
		}
	}
	for (int i = 0; i < n; i++)
	{
		update(maxx + 1, h[i] + 1, 1);
		int sum = getSum(h[i] + 1);
		cnt[i] += i + 1 - sum;
	}
	mst(c, 0);
	for (int i = n - 1; i >= 0; i--)
	{
		update(maxx + 1, h[i] + 1, 1);
		cnt[i] += getSum(h[i]);
	}
	for (int i = 0; i < n; i++)
	{
		ans += (cnt[i] + 1) * cnt[i] / 2;
	}
	cout << ans << endl;
	return 0;
}
发布了60 篇原创文章 · 获赞 2 · 访问量 1610

猜你喜欢

转载自blog.csdn.net/qq_44624316/article/details/104704631