时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个长度为N的数组A1, A2, ... AN,恰好是1~N的一个排列。请你计算所有连续子数组Al, Al+1, ... Ar的逆序对数目之和是多少。(1 <= l < r <= N)
输入
第一行包含一个整数N。
第二行包含N个整数,A1, A2, ... AN。恰好是1~N的一个排列。
对于30%的数据,1 <= N <= 1000
对于60%的数据,1 <= N <= 10000
对于100%的数据,1 <= N <= 100000
输出
一个整数代表答案。
样例输入
5 5 1 2 3 4
样例输出
10
题目链接:https://hihocoder.com/problemset/problem/1926
题目分析:考虑每个数字本身对答案的贡献,对于一个数字x,需要得到两个值,一是其之后比其小的数的个数,二是x在原数组中从前往后数的位置,因要求所有连续子数组,故x之后比其小的数的个数需要重复累加,累加的部分恰好是其在原数组中从后往前数的位置,举个例子
a[] = 3 1 5 2 4
i ans b[]
5 0 0 0 0 1 0
4 0 0 2 0 1 0
3 9 0 2 0 1 3
2 9 4 2 0 1 3
1 15 4 2 5 1 3
b[i]指的是数字i在a数组中是从后往前数的第几个,下面说明i=3时ans的9是如何计算出来的:
i=3时,a[i]=5,5之后比其小的数的个数通过树状数组求出来是3,这里的3包括了1组5和4的逆序和2组5和2的逆序,即(524,52,524),5在原数组中从前往后数是第3个,因此ans=3*3=9,这里乘3是为了加上前缀,即
(524,52,524)
(1524,152,1524)
(31524,3152,31524) 这里的三个只是标记54在31524中存在,52在3152中存在,52在31524中存在,上同
i=5时同理
#include <cstdio>
#define ll long long
int const MAX = 100005;
int a[MAX], n;
ll c[MAX];
int lowbit(int x) {
return x & (-x);
}
void update(int x, int val) {
for (int i = x; i <= n; i += lowbit(i)) {
c[i] += val;
}
}
ll query(int x) {
ll ans = 0;
for (int i = x; i > 0; i -= lowbit(i)) {
ans += c[i];
}
return ans;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
ll ans = 0;
for (ll i = n; i > 0; i--) {
ans += i * query(a[i] - 1);
update(a[i], n - i + 1);
}
printf("%lld\n", ans);
}