题目链接:
PREV-31 小朋友排队
思路:
分析题意不难理解出某个人的移动次数为(排在他前面比他高的人数+排在他后面比他矮的人数);
使用树状数组可以高效地计算得到上面两项数据(使用时注意将每个人的身高加1,因为有0身高的存在);
每个人的不高兴程度就是
,其中
代表此人的移动次数;
代码:
#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;
}