【每日蓝桥】57、一八年省赛Java组真题“递增三元组”

该博客分享了蓝桥杯省赛Java组的真题——递增三元组问题,解析了两种解题思路,包括错误的遍历解法和正确的优化算法,并提供了正确答案源码。博主灰小猿通过实例讲解算法思想和数据结构,邀请读者一起学习讨论。
摘要由CSDN通过智能技术生成

你好呀,我是灰小猿,一个超会写bug的程序猿!

欢迎大家关注我的专栏“每日蓝桥”,该专栏的主要作用是和大家分享近几年蓝桥杯省赛及决赛等真题,解析其中存在的算法思想、数据结构等内容,帮助大家学习到更多的知识和技术!

标题:递增三元组

给定三个整数数组

A=[A1,A2,…AN],
B=[B1,B2,…BN],
C=[C1,C2,…CN],

请你统计有多少个三元组 (i,j,k)

满足:

  1. 1≤i,j,kN
  2.  Ai<Bj<Ck

输入格式

第一行包含一个整数 N

第二行包含 N个整数 A1,A2,…AN

第三行包含 N个整数 B1,B2,…BN

第四行包含 N个整数 C1,C2,…CN

输出格式

一个整数表示答案。

数据范围

1≤N≤10^5
0≤Ai,Bi,Ci≤10^5

输入样例:

3

1 1 1

2 2 2

3 3 3

输出样例:

27

 

资源约定: .

峰值内存消耗(含虚拟机) < 256M

CPU消耗< 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“ 请您输...”的多余内容.

所有代码放在同-一个源文件中,调试通过后,拷贝提交该源码.

不要使用package语句。不要使用jdk1.7及以上版本的特性。

主类的名字必须是: Main, 否则按无效代码处理.

解题思路

本题在求解上主要还是要理解题意,对于这样一个在三个数组中找结果的提醒,很多同学想到的第一个思路应该就是遍历三个数组进行求解,在理论上这种方法是可行的,但是只是对于少量的数据,对于题中所给的数据,10^5遍历三次也就是10的15次方,这个数据是十分庞大的,所以对于该题来说是行不通的,那么我们其实可以想办法对这种方法进行优化,尽可能的减少遍历的次数。

其实对于这个题的其他解法是:用数组A[i]中对应的数后面找到一个对应B数组的一段数据,再用B[i]找出C数组中符合要求的数据。用下图来表示:

另一种解法,以B数组中的元素为参考,找出A数组中小于B数组的元素数量p,再找出C数组中大于B数组的元素数量q,则对于B[i]符合要求的数据数就是p*q个:但是这种方法在运算时,每对ans答案增加一次时,都要乘以1L,原因是因为数据在很大的时候是需要变成long型的,关于1L的解释入下:

 java中经常会碰到“long c = 1L”的写法,L表示long ,long占用8个字节,表示范围:-9223372036854775808 ~ 9223372036854775807 
1L其实就是1。
常量后面跟这个一般是指类型,1L表示1是长整型,如果是1f 表示是float型

关于这一种解法如下图:

但是该解法最后对于超大量数据是不符合要求的,尝试了很多次还是不行,不知道是为什么,但是思路结构和第二种方法差不多,但是第二种方法就是正确答案,有些疑惑,知道为什么的小伙伴可以留言一起解答,下面把这两种解法的代码都奉上:

答案源码:

第一种解法(大量数据时运算有误)

package 一八年省赛真题;

import java.sql.Array;
import java.util.Arrays;
import java.util.Scanner;

public class Year2018_Bt6 {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int N = scanner.nextInt();
		int [] A = new int[N];
		int [] B = new int[N];
		int [] C = new int[N];
		
		for (int i = 0; i < N; i++) {
			A[i] = scanner.nextInt();
		}
		for (int i = 0; i < N; i++) {
			B[i] = scanner.nextInt();
		}
		for (int i = 0; i < N; i++) {
			C[i] = scanner.nextInt();
		}
		
		//对输入的三个数组进行升序排列
		Arrays.sort(A);
		Arrays.sort(B);
		Arrays.sort(C);
		
		long ans = 0;
		int p = 0,q = 0;	//定义一个p,q来分别表示在数组B,C中从哪一位开始的数是大于前一个数组对应数的
		for (int i = 0; i < N; i++) {
			//找出第一个大于A[i]的数
			while(p<N && A[i]>=B[p]) p++;
			int cq = 0;
			//将B数组中剩下的数进行遍历
			for (int j = p; j < N; j++) {
				//找出第一个大于B[j]的数
				while(q<N && B[j]>=C[q]) q++;
				//记录下每一次的起始数,为了减少下次遍历
				if(j == p) cq=q;
				ans += (N-q);
			}	
			q=cq;
		}
		System.out.println(ans);
	}

}

第二种解法(完全正确)

package 一八年省赛真题;

import java.util.Arrays;
import java.util.Scanner;


public class Year2018_Bt6_2 {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int N = scanner.nextInt();
		int [] A = new int[N];
		int [] B = new int[N];
		int [] C = new int[N];
		
		for (int i = 0; i < N; i++) {
			A[i] = scanner.nextInt();
		}
		for (int i = 0; i < N; i++) {
			B[i] = scanner.nextInt();
		}
		for (int i = 0; i < N; i++) {
			C[i] = scanner.nextInt();
		}
		
		//对输入的三个数组进行升序排列
		Arrays.sort(A);
		Arrays.sort(B);
		Arrays.sort(C);
		
		int p = 0, q = 0;
		long ans = 0;	//由于数据比较大,所以定义为long型
		for (int i = 0; i < N; i++) {
			while(p<N && A[p]<B[i]) p++;
			
			while(q<N && B[i]>=C[q]) q++;
			ans += 1L*p*(N-q);	//乘以1L的目的是为了让结果称为long型
		}
		System.out.println(ans);

	}

}

输出样例:

 

其中有不足或者改进的地方,还希望小伙伴留言提出,一起学习!

感兴趣的小伙伴可以关注专栏!

灰小猿陪你一起进步!

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灰小猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值