CJOJ 2398 簡單的數列

簡單的數列

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章