簡單的數列
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、求和不能超過數組的範圍!