视频加载失败

最大上升三元组数量

467 字
2 分钟
最大上升三元组数量

数组离散化 树状数组 前缀和

思路#

要求统计满足 i<j<ki < j < k 且 ai<aj<aka_i < a_j < a_k 的上升三元组数量。把每个位置 jj 当作三元组的中间元素,问题拆成两步:

  • 第一层(树状数组 f1):从左往右扫描,f1.add(idx, 1) 记录值 idx 出现次数。对当前值 idx,f1.query(idx - 1) 就是它左边比它小的数的个数,记作 smalljsmall_j。
  • 第二层(树状数组 f2):f2.add(idx, small_j),即在位置 idx 上累加「以某个值结尾、且比它小的左边元素数」。这样 f2.query(idx - 1) 累计的就是所有「两两上升对」中,右端值比 idx 小的对数。

扫到 i 时执行 ans += f2.query(idx - 1),即以 aia_i 作为第三个元素,能接上的上升对数量。三层递推:单个数 → 上升对 → 上升三元组。

值域可能很大(long long),所以先对数组离散化(排序副本 + lower_bound 映射),再把离散化后的排名当作树状数组下标。

复杂度 O(nlog⁡n)O(n \log n),空间 O(n)O(n)。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e4+10;
typedef long long ll;
class MyTree {
public:
vector<int> v;
int sz;
MyTree(int sz) {
this->sz = sz;
v.resize(sz + 1);
}
int lowbit(int x) {
return x & (-x);
}
void add(int x, int value) {
while (x <= sz) {
v[x] += value;
x += lowbit(x);
}
}
int query(int x) {
int sum = 0;
while (x > 0) {
sum += v[x];
x -= lowbit(x);
}
return sum;
}
};
MyTree f1(MAXN), f2(MAXN);
void solve() {
int n;
cin >> n;
vector<ll> arr(n + 1);
vector<ll> sorted_arr(n + 1);
for (int i = 1; i <= n; i++) {
cin >> arr[i];
sorted_arr[i] = arr[i]; // 复制数组用于排序
}
sort(next(begin(sorted_arr)), end(sorted_arr)); // 仅排序副本
auto f = [&](ll x) {
return lower_bound(next(begin(sorted_arr)), end(sorted_arr), x) - sorted_arr.begin();
};
ll ans = 0;
for (int i = 1; i <= n; i++) {
int idx = f(arr[i]);
f1.add(idx, 1);
f2.add(idx, f1.query(idx - 1)); // 确保索引合法
ans += f2.query(idx - 1);
}
cout << ans << endl;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
solve();
return 0;
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

最大上升三元组数量
https://blog.81vm3.xyz/posts/max-increasing-triples/
作者
Blume
发布于
2024-12-01
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Blume
I build interesting things.
公告
欢迎来到我的博客!
分类
标签
最新动态
站点统计
文章
38
分类
5
标签
98
总字数
23,078
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.16.8
文章许可
CC BY-NC-SA 4.0
文章目录