AcWing 1236. 递增三元组 (flag + 前缀和 | 二分 | 滑动窗口)
1236. 递增三元组
解题思路
- 最开始想到3重循环枚举三个数组,然后最内层用条件语句判断一下即可,但是数据范围为10510^5105,三重循环肯定会超时
- 那么这道题很可能需要的算法复杂度为O(n)O(n)O(n)或O(nlogn)O(nlogn)O(nlogn),所以只能枚举一个数组,那么枚举哪一个呢?
- 根据题目来看,要求Ai<Bj<CkA_i<B_j<C_kAi<Bj<Ck,那么就来枚举B数组
- 此时我们只需要找到A数组中所有小于BjB_jBj的数和C数组中所有大于BjB_jBj的数,然后将这两个数乘起来就是ans
- 如何找到A数组中所有小于BjB_jBj的数和C数组中所有大于BjB_jBj的数且在遍历B数组的for循环内部的时间复杂度要低于O(n)
- 方法一:flag + 前缀和
- 方法二:排序 + 二分
- 方法三:滑动窗口
方法一:flag + 前缀和 O(n)
思路:
- 计数排序思想:先初始化flag数组用来记录a数组每个数出现的次数
- 计算flag数组的前缀和数组 s[n],那么 s[i] 就表示从a数组中所有取值在 [0, i] 区间内的元素个数
- 那么计数 a数组 中所有小于 b[j] 的数就相当于求a数组中取值在 [0, b[j] - 1] 区间内的元素个数,即求s[b[j] - 1],b数组同理
import java.util.*;
import java.io.*;
import java.math.*;class Main {BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));String sp[];int N = 100010;int[] a = new int[N], b = new int[N], c = new int[N];int n;int[] flag_a = new int[N];int[] s_flag_a = new int[N];int[] flag_c = new int[N];int[] s_flag_c = new int[N];void run() throws Exception {sp = reader.readLine().split(" ");n = Integer.parseInt(sp[0]);sp = reader.readLine().split(" ");for (int i = 0; i < n; i++) {a[i] = Integer.parseInt(sp[i]);}sp = reader.readLine().split(" ");for (int i = 0; i < n; i++) {b[i] = Integer.parseInt(sp[i]);}sp = reader.readLine().split(" ");for (int i = 0; i < n; i++) {c[i] = Integer.parseInt(sp[i]);}// 用a数组初始化flag_a数组for (int i = 0; i < n; i++) {flag_a[a[i]]++;flag_c[c[i]]++;}s_flag_a[0] = flag_a[0];s_flag_c[0] = flag_c[0];// 得到flag_a数组和flag_c数组的前缀和数组for (int i = 1; i < N; i++) {s_flag_a[i] = s_flag_a[i - 1] + flag_a[i];s_flag_c[i] = s_flag_c[i - 1] + flag_c[i];}BigInteger cnt = new BigInteger("0");// 遍历b数组for (int i = 0; i < n; i++) {BigInteger cnt_a = new BigInteger(String.valueOf(b[i] - 1 < 0 ? 0 : s_flag_a[b[i] - 1]));BigInteger cnt_c = new BigInteger(String.valueOf(n - s_flag_c[b[i]]));cnt = cnt.add(cnt_a.multiply(cnt_c));}System.out.println(cnt);}public static void main(String[] args) throws Exception {new Main().run();}
}
方法二:排序 + 二分 O(nlogn)
注意:
- 二分的条件必须为:a数组和b数组中有一部分大于b[i]和小于b[i]的数,需要特判一下全小于等于或者全大于等于b[i]的情况,否则二分会出错
Arrays.sort(int[] arr, int startIndex, int endIndex)
时需要注意的是[startIndex, endIndex),和substring一样- N的数据范围为10510^5105,那么最多可能出现的次数为101010^{10}1010会爆long,所以要用大数类
- 大数类的运算方法不会直接修改大数的值,需要重新赋值
- 调试技巧:当二分出现错误的时候从两个方向考虑,排序和二分
import java.util.*;
import java.io.*;
import java.math.*;class Main {BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));String sp[];int[] a = new int[100010], b = new int[100010], c = new int[100010];int n;void run() throws Exception {sp = reader.readLine().split(" ");n = Integer.parseInt(sp[0]);sp = reader.readLine().split(" ");for (int i = 0; i < n; i++) {a[i] = Integer.parseInt(sp[i]);}sp = reader.readLine().split(" ");for (int i = 0; i < n; i++) {b[i] = Integer.parseInt(sp[i]);}sp = reader.readLine().split(" ");for (int i = 0; i < n; i++) {c[i] = Integer.parseInt(sp[i]);}// 对a数组和c数组先排序Arrays.sort(a, 0, n);Arrays.sort(c, 0, n);BigInteger cnt = new BigInteger("0");// 遍历b数组for (int i = 0; i < n; i++) {BigInteger cnt_a = new BigInteger("0"); BigInteger cnt_c = new BigInteger("0");;// 从a数组中找到所有小于b[i]的数// 其最大值比b[i]还小那么cnt_a = n// 其最小值不小于b[i]那么cnt_a = 0// 有一部分小于b[i],一部分大于b[i],则用二分找到第一个大于b[i]的数的下标if (a[n - 1] < b[i]) cnt_a = new BigInteger(String.valueOf(n));else if (a[0] >= b[i]) cnt_a = new BigInteger(String.valueOf(0));else cnt_a = new BigInteger(String.valueOf(searchFirstBigOrEqualNum(b[i])));// 从c数组中找到所有大于b[i]的数// 其最小值比b[i]还那么cnt_c = n// 其最大值不大于b[i]那么cnt_c = 0if (c[0] > b[i]) cnt_c = new BigInteger(String.valueOf(n));else if (c[n - 1] <= b[i]) cnt_c = new BigInteger(String.valueOf(0));else cnt_c = new BigInteger(String.valueOf(n - searchFirstBigNum(b[i]))); cnt = cnt.add(cnt_a.multiply(cnt_c));}System.out.println(cnt);}int searchFirstBigOrEqualNum(int target) {int l = 0, r = n - 1;while (l < r) {int mid = (l + r) / 2;if (a[mid] < target) {l = mid + 1;} else {r = mid;}}return l;}int searchFirstBigNum(int target) {int l = 0, r = n - 1;while (l < r) {int mid = (l + r) / 2;if (c[mid] <= target) {l = mid + 1;} else {r = mid;}}return l;}public static void main(String[] args) throws Exception {new Main().run();}
}
AcWing 1236. 递增三元组 (flag + 前缀和 | 二分 | 滑动窗口)相关推荐
- 【CodeForces - 514D】R2D2 and Droid Army(二分+滑动窗口ST表,或 尺取+单调队列或STLmultiset)
题干: An army of n droids is lined up in one row. Each droid is described by m integers a1, a2, ..., a ...
- 跳跃游戏 (动态规划剪枝/前缀和/滑动窗口/BFS剪枝)
一.跳跃游戏简单介绍 1. 跳跃游戏简单介绍 跳跃游戏是一种典型的算法题目,经常是给定一数组arr,从数组的某一位置i出发,根据一定的跳跃规则,比如从i位置能跳arr[i]步,或者小于arr[i]步, ...
- [蓝桥杯][2018年第九届真题] 递增三元组、螺旋折线、日志统计、全球变暖、乘积最大
个人题解链接,历届试题,正在更新中~ 题目目录 递增三元组 螺旋折线 日志统计 全球变暖 乘积最大 递增三元组 给定三个整数数组 A = [A1, A2, - AN], B = [B1, B2, - ...
- [Leedcode][JAVA][第209题][长度最小的子数组][滑动窗口][前缀和][二分查找][双指针]
[问题描述][中等] 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组,并返回其长度.如果不存在符合条件的连续子数组,返回 0.示例: 输入: ...
- 递增三元组蓝桥杯c语言,蓝桥-递增三元组-蓝桥
蓝桥-递增三元组-蓝桥 蓝桥-递增三元组-蓝桥 手动求解一下会发现,B数组是关键 若固定b = B[i] a中的可能的取值是:a0 ----- at小于等于b的元素下标(小于b的个数) c中的可能取值 ...
- 2018省赛第九届蓝桥杯真题C语言B组第六题题解 递增三元组
2018第九届蓝桥杯C++省赛B组[最新题解汇总] 标题:递增三元组 给定三个整数数组 A = [A1, A2, ... AN], B = [B1, B2, ... BN], C = [C1, C ...
- Gym - 101911B Glider(前缀和+二分)
传送门:点我 A plane is flying at a constant height of hh meters above the ground surface. Let's consider ...
- HDU 6406 Taotao Picks Apples(前缀和+二分)
HDU 6406 Taotao Picks Apples(前缀和+二分) Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 131072/131 ...
- poj3061尺取法/前缀和 二分(java)
今天遇到这题因为以前没见到过,当时就是想着应该有着一个很简单的方法可以过但是奈何就是没思路.后来看了别人思路写了下来.学习了尺取法 poj3061 题目介绍: Description A sequen ...
最新文章
- Java知多少(15)字符串
- Vue中使用LayUI没有效果
- 得力助手 消防员的 消防机器人_消防机器人:消防员的“得力助手”
- WordPress快速打造个人博客
- 一段javascript告警回放代码
- php+oracle新增数据类型,Oracle 修改某个字段的数据类型三种方式
- 《Photoshop Lightroom4 经典教程》—第1课复习题答案
- SwiftUI 打开高德地图
- model存储 swift_使用Swift原生JSON-Model
- Mysql查询结果导出为Excel的几种方法
- wordpresd免登录发布接口php_实现wordpress的ajax接口请求学会admin-ajax.php的利用
- mongodb删除某个字段
- 上海计算机科学大学排名,2019上海软科世界一流学科排名计算机科学与工程专业排名卡耐基梅隆大学排名第4...
- Java项目经验之交易密码安全机制
- python群发邮件 不进垃圾箱_邮件群发不进垃圾箱
- [高数][高昆轮][高等数学上][第一章-函数与极限]03.函数的极限
- 复习单片机:动态数码管(1 数码管介绍+2 74HC245 和 74HC138 芯片介绍+3 硬件设计+4 软件设计+5 实验现象)
- 未知的类型名‘ulong_t’解决
- 51单片机和Arduino有什么区别?
- 配置Samba服务器