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

题目链接:

PREV-31 小朋友排队

思路:

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

代码:

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值