《P1637 三元上升子序列》
题目描述
Erwin 最近对一种叫 thair
的东西巨感兴趣。。。
在含有 n 个整数的序列 a1,a2,…,an 中,三个数被称作thair
当且仅当 i<j<k 且 ai<aj<ak。
求一个序列中 thair
的个数。
输入格式
开始一行一个正整数 n,
以后一行 n 个整数 a1,a2,…,an。
输出格式
一行一个整数表示 thair
的个数。
输入输出样例
输入 #1复制
4 2 1 3 4
输出 #1复制
2
输入 #2复制
5 1 2 2 3 4
输出 #2复制
7
说明/提示
样例2 解释
7 个 thair
分别是:
- 1 2 3
- 1 2 4
- 1 2 3
- 1 2 4
- 1 3 4
- 2 3 4
- 2 3 4
数据规模与约定
- 对于 30% 的数据 保证 n≤100;
- 对于 60% 的数据 保证 n≤2000;
- 对于 100% 的数据 保证 1≤n≤3×104,1≤ai≤105。
代码实现:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 树状数组类
class FenwickTree {
private:
vector<int> tree;
int size;
public:
FenwickTree(int n) : size(n), tree(n + 1, 0) {}
void update(int idx) {
while (idx <= size) {
tree[idx]++;
idx += idx & -idx;
}
}
int query(int idx) {
int sum = 0;
while (idx > 0) {
sum += tree[idx];
idx -= idx & -idx;
}
return sum;
}
};
int main() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
// 离散化处理
vector<int> b = a;
sort(b.begin(), b.end());
b.erase(unique(b.begin(), b.end()), b.end());
// 计算left[j]:j之前小于a[j]的元素个数
vector<int> left(n, 0);
FenwickTree ft1(b.size());
for (int j = 0; j < n; j++) {
int idx = lower_bound(b.begin(), b.end(), a[j]) - b.begin() + 1;
left[j] = ft1.query(idx - 1);
ft1.update(idx);
}
// 计算right[j]:j之后大于a[j]的元素个数
vector<int> right(n, 0);
FenwickTree ft2(b.size());
for (int j = n - 1; j >= 0; j--) {
int idx = lower_bound(b.begin(), b.end(), a[j]) - b.begin() + 1;
// j之后的元素总数是n-1-j个
// ft2.query(idx)表示到当前为止(从右到左)小于等于a[j]的元素个数
// 所以right[j] = (j之后的元素总数) - (小于等于a[j]的元素个数)
right[j] = (n - 1 - j) - ft2.query(idx);
ft2.update(idx);
}
// 计算所有thair的数量
long long count = 0;
for (int j = 0; j < n; j++) {
count += (long long)left[j] * right[j];
}
cout << count << endl;
return 0;
}