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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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、求和不能超过数组的范围!


你可能感兴趣的:(考试,树)