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

[题目概述]

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

输入格式

第一行包含一个整数 N。
第二行包含 N 个整数 A 1 , A 2 , … A N A_1,A_2,…A_N A1,A2,AN
第三行包含 N 个整数 B 1 , B 2 , … B N B_1,B_2,…B_N B1,B2,BN
第四行包含 N 个整数 C 1 , C 2 , … C N C_1,C_2,…C_N C1,C2,CN

输出格式

一个整数表示答案。

数据范围

1 ≤ N ≤ 1 0 5 10^5 105,
0≤ A i , B i , C i A_i,B_i,C_i Ai,Bi,Ci 1 0 5 10^5 105

输入样例:
3
1 1 1
2 2 2
3 3 3
输出样例:
27
  • 分析题目
    题目就是让我们从三组数中选出三个数,满足A中的数小于B中的数小于C中的数。那么我们最先想到的就是三重循环分别枚举三个数,但很显然会超时,因为1 ≤ N ≤ 1 0 5 10^5 105,所以我们最多只能枚举一个数,如果我们枚举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 
#include 
#include 
#include 

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;
}
  • 本题就分享完毕了,有问题的小伙伴可以在评论区留言
    记得点赞关注加收藏!

你可能感兴趣的:(算法,c++,数据结构)