原题链接:AcWing 1236. 递增三元组(蓝桥杯辅导课) - AcWing
题意:给定三元组,从上到下每组找一个元素构成递增关系,不能相等
思路
思路简单,先过一遍样例
发现选定第一位时,可以在第二组里找有多少大于这一位,再在第三组里找有多少大于第二组的
如果遍历实现肯定超时,考虑到:
- 第二组,找到第一个比当前大的第一个数作为分界点
- 第三组,找到比第二个数大的数作为分界点 考虑二分
当找到第一组选定的数,对应的每个第二组的大于这个数的数的索引时,包括这个数在内的后面的数都可以选(假定已经排好序), 那么这些数对应的第三组的数也都可以选,所以目标是找到分界点,由于相加数量级别大,考虑前缀和
实现
实现时要注意理清楚二分要找什么值 由于考虑前缀和,对第二组二分时考虑的是最后一个小于等于当前数的索引(用于前缀和)
第三组要找的是,考虑第一个大于当前数的索引(要用n-l+1来确定其后有多少选择)
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int a[N], b[N], c[N];
LL sum[N];
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; i ++)
cin >> a[i];
for(int i = 1; i <= n; i ++)
cin >> b[i];
for(int i = 1; i <= n; i ++)
cin >> c[i];
sort(a+1, a + n + 1);
sort(b + 1, b + n + 1);
sort(c + 1, c + n + 1);
//二分
int idxa = 0;
for(int i = 1; i <= n; i ++)
{
//找到最后一个比自己小的
int l = 1, r = n;
while(l < r)
{
int mid = (l + r + 1) >> 1;
if(b[mid] <= a[i]) l = mid;
else r = mid - 1;
}
idxa = i;
if(b[l] > a[i]) a[i] = 0;
else a[i] = l;
}
int idxb = 0;
for(int i = 1; i <= n; i ++)
{
//找到第一个比自己大的
int l = 1, r = n;
while(l < r)
{
int mid = (l + r ) >> 1;
if(c[mid] > b[i]) r = mid;
else l = mid + 1;
}
// 记录下每个b可以选哪些数
idxb = i;
if(c[l] <= b[i]) b[i] = 0;
else b[i] = n - l + 1;
}
for(int i = 1; i <= idxb; i ++)
{
//前缀和
sum[i] += sum[i-1] + b[i];
//cout << sum[i] << endl;
}
/*for(int i = 1; i <= n; i ++)
{ cout << b[i] << endl;
cout << a[i] << endl;}*/
LL ans = 0;
for(int i = 1; i <= idxa; i ++)
{
//a对应的b可以选的全部数
ans += sum[idxb] - sum[a[i]];
//cout << ans;
}
cout << ans << endl;
return 0;
}