蓝桥杯 PREV-31 小朋友排队(树状数组)

题目链接:

PREV-31 小朋友排队

思路:

分析题意不难理解出某个人的移动次数为(排在他前面比他高的人数+排在他后面比他矮的人数);
使用树状数组可以高效地计算得到上面两项数据(使用时注意将每个人的身高加1,因为有0身高的存在);
每个人的不高兴程度就是 a i ( a i + 1 ) 2 \frac{a_i(a_i+1)}{2} ,其中 a i a_i 代表此人的移动次数;

代码:

#include<bits/stdc++.h>

using namespace std;

const int maxn = 1e5 + 5;
int n, top, h[maxn], bit[1000005];
long long cnt[maxn];
inline void add(int i) {
	while(i <= top) ++bit[i], i += i & -i;
}
inline int sum(int i) {
	int s = 0;
	while(i) s += bit[i], i -= i & -i;
	return s;	
}

int main() {
#ifdef MyTest
	freopen("Sakura.txt", "r", stdin);
#endif
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) scanf("%d", &h[i]), ++h[i], top = max(top, h[i]);
	for(int i = 1; i <= n; ++i) {
		add(h[i]);
		cnt[i] = i - sum(h[i]);
	}
	memset(bit, 0, sizeof(bit));
	for(int i = n; i >= 1; --i) {
		add(h[i]);
		cnt[i] += sum(h[i] - 1);
	}
	long long ans = 0;
	for(int i = 1; i <= n; i++) ans += (cnt[i] + 1) * cnt[i] >> 1;
	printf("%lld", ans);
	return 0;
}
发布了356 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_45228537/article/details/104498449