递增三元组个数的三种思路(附代码)
问题描述
这是蓝桥杯模拟赛的一道题目,给定数列,寻找递增三元组的数目,具体如下图:
思路
- 穷举所有三元组,检查是否符合a_i < a_j < a_k ,符合则count+=1,时间复杂度为O(n^3),只能过50%的点
- 对a_i,遍历其左边的数,比它小则 pre[i] += 1,比它大则 post[i] += 1 ,最后求 pre[i] * post[i] 即以 i 为中心的三元组个数, 复杂度为O(n^2) , 只能过80% 的点
- 观察思路2,我们发现每次求pre[i]和post[i]我们需要花O(n)的复杂度,这一步可以使用树状数组来优化,时间复杂度为O(nlogn) , 详见代码注释
代码
思路2 O(n^2)
#include<iostream>
using namespace std;
const int maxn = 1e5 + 7;
int a[maxn]; //输入的数据
long long pre[maxn], post[maxn];//数k的左边有多少个数,右边有多少个数
long long ans=0;//递增三元组个数
int main()
{
int n; cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
for (int j = 1; j < i; j++) {
if (a[j] < a[i]) pre[i]++;
}
for (int j = i + 1; j <= n; j++) {
if (a[j] > a[i]) post[i]++;
}
}
for (int i = 1; i <= n; i++) {
ans += pre[i] * post[i];
}
cout << ans;
return 0;
}
思路3 O(nlogn)
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 1e5 + 7;
int a[maxn]; //输入的数据
long long pre[maxn], post[maxn];//数k的左边有多少个数,右边有多少个数
const int maxn2=100 + 7;//数值范围1~100
int C[maxn];//部分和
long long ans=0;//递增三元组个数
int lowbit(int x) { return x & -x; }
int sum(int x) {
int res = 0;
while (x > 0) {
res += C[x];
x -= lowbit(x);
}
return res;
}
void update(int x) {
while (x <= maxn2) {
x += lowbit(x);
C[x] += 1;
}
}
int main()
{
int n; cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
//在线处理,从左往右看
memset(C, 0, sizeof(C));
for (int i = 1; i <= n; i++) {
pre[i] = sum(a[i] - 1);//数值为1~(a[i]-1)的元素个数
update(a[i]);
}
memset(C, 0, sizeof(C));
//从右往左看
for (int i = n; i >=1; i--) {
int x1 = sum(maxn2);
int x2 = sum(a[i] + 1);
post[i] = x1-x2;//数值为(a[i]+1)~maxn的元素个数
update(a[i]);
}
for (int i = 1; i <= n; i++) {
ans += pre[i] * post[i];
}
cout << ans;
return 0;
}