简单的数列
Description
一个简单的数列问题:
给定一个长度为n的数列,求这样的三个元素 ai,aj,ak 的个数,满足 ai<aj>ak,且 i<j<k 。
Input
第1行是一个整数n(1<=n<=50000)。
接下来n行,每行一个元素ai(0<=ai<=32767)。
Output
一个数,满足 ai<aj>ak (i<j<k) 的个数。
Sample Input
5
1
2
3
4
1
Sample Output
6
Hint
数据范围:
对于30%的输入数据有n<=200。
对于80%的输入数据有n<=10000。
对于100%的输入数据有n<=50000。
Source
归并排序, 树状数组 ,线段树,平衡树
Solution
树状数组算两次逆序对(从前往后一次,从后往前一次),最后将两次结果相乘加入ans即可
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <queue>
#define L 50010
#define LL long long
using namespace std;
int n, c[L], a[L], q1[L], q2[L];
LL ans;
inline int lowbit (int x) {
return x & (-x);
}
inline void updata(int x, int v) {
for (int i = x; i <= 32777; i += lowbit(i)) c[i] += v;
}
inline int sum(int x) {
int ans = 0;
for (int i = x; i; i -= lowbit(i)) ans += c[i];
return ans;
}
int main() {
freopen("queueb.in", "r", stdin);
freopen("queueb.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), a[i]++;
for (int i = 1; i <= n; ++i) {
q1[i] = sum(a[i] - 1);
updata(a[i], 1);
}
memset(c, 0, sizeof(c));
for (int i = n; i >= 1; --i) {
q2[i] = sum(a[i] - 1);
updata(a[i], 1);
}
for (int i = 1; i <= n; ++i) ans += (q1[i] * q2[i]);
printf("%lld\n", ans);
return 0;
}
Summary
1、切记输入的每一个数都要加1,因为有为0的情况(考试痛失40分)
2、树状数组每一次操作的复杂度是O(logn),不是O(nlogn),差点算错了复杂度
3、求和不能超过数组的范围!