AcWing 1236.递增三元组(看似枚举实则二分)

文章介绍了使用二分查找优化求解给定整数数组A、B、C中满足A_i<B_j<C_k条件的三元组个数的方法。

[题目概述]

给定三个整数数组
A=[A1,A2,…AN],A=[A_1,A_2,…A_N],A=[A1,A2,AN],
B=[B1,B2,…BN],B=[B_1,B_2,…B_N],B=[B1,B2,BN],
C=[C1,C2,…CN],C=[C_1,C_2,…C_N],C=[C1,C2,CN],
请你统计有多少个三元组 (i,j,k)
满足:
1≤i,j,k≤N1 ≤ i, j, k ≤ N1i,j,kN
Ai<Bj<CkA_i < B_j < C_kAi<Bj<Ck

输入格式

第一行包含一个整数 N。
第二行包含 N 个整数 A1,A2,…ANA_1,A_2,…A_NA1,A2,AN
第三行包含 N 个整数 B1,B2,…BNB_1,B_2,…B_NB1,B2,BN
第四行包含 N 个整数 C1,C2,…CNC_1,C_2,…C_NC1,C2,CN

输出格式

一个整数表示答案。

数据范围

1 ≤ N ≤ 10510^5105,
0≤ Ai,Bi,CiA_i,B_i,C_iAi,Bi,Ci10510^5105

输入样例:
3
1 1 1
2 2 2
3 3 3
输出样例:
27
  • 分析题目
    题目就是让我们从三组数中选出三个数,满足A中的数小于B中的数小于C中的数。那么我们最先想到的就是三重循环分别枚举三个数,但很显然会超时,因为1 ≤ N ≤ 10510^5105,所以我们最多只能枚举一个数,如果我们枚举A中的数,那么B C 是有联系的,我们无法往下计算,但如果我们枚举B中的数,A C 是相互独立的,那么我们只要从A中选出小于当前枚举的B中的数,从C中选出大于当前枚举的B的数就可,分析到这里就可以想到用二分法来解了。代码相对不是那么难写。
  • 细节问题
    • 二分法枚举后,符合条件的数有多少呢?
      A中的数量应该是 l + 1 个而不是 l 个,因为我们的下标从0开始。
      C中的数量应该是 n - l 个而不是 n - 1 - l 个。
    • 边界问题处理
    if (a[l] >= b[j])
    		l = -1;
    
    if (c[p] <= b[j])
    		p = n;
    
  • 完整代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;
const int N = 100005;
int a[N], b[N], c[N];
int n, sum;
int main () {
	cin >> n;
	for (int i = 0; i < n; i ++)
		cin >> a[i];
	for (int i = 0; i < n; i ++)
		cin >> b[i];
	for (int i = 0; i < n; i ++)
		cin >> c[i];
	for (int j = 0; j < n; j ++) {
		sort(a, a + n);
		sort(c, c + n);
		int l = 0, r = n - 1;
		while (l < r) {
			int mid = (l + r + 1) / 2;
			if (a[mid] < b[j])
				l = mid;
			else
				r = mid - 1;
		}
		if (a[l] >= b[j])
			l = -1;
		int p = 0, q = n - 1;
		while (p < q) {
			int mid = (p + q) / 2;
			if (c[mid] > b[j])
				q = mid;
			else
				p = mid + 1;
		}
		if (c[p] <= b[j])
			p = n;

		sum += (l + 1) * (n - p); // A C 是相互独立的,数量应该乘起来
	}
	cout << sum << endl;
	return 0;
}
  • 本题就分享完毕了,有问题的小伙伴可以在评论区留言
    记得点赞关注加收藏!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值