备战蓝桥杯,用JAVA刷洛谷算法题单:【算法2-2】常见优化技巧

参考

【算法2-2】常见优化技巧 - 题单 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

image-20240314135443776

  • P1102 A-B 数对
  • P1638 逛画展
  • P1115 最大子段和
  • P7072 [CSP-J2020] 直播获奖
  • P2671 [NOIP2015 普及组] 求和
  • P4147 玉蟾宫
  • P2866 [USACO06NOV] Bad Hair Day S
  • P1950 长方形
  • P2032 扫描
  • P2216 [HAOI2007] 理想的正方形
  • UVA11572 唯一的雪花 Unique Snowflakes
  • P4653 [CEOI2017] Sure Bet
  • P3143 [USACO16OPEN] Diamond Collector S
  • P7910 [CSP-J 2021] 插入排序
  • P1578 奶牛浴场
  • P3467 [POI2008] PLA-Postering
  • P1886 滑动窗口 /【模板】单调队列
  • P2880 [USACO07JAN] Balanced Lineup G
  • P1714 切蛋糕
  • P1725 琪露诺

双指针

一般来说双指针可以优化原本需要O(n2)时间的遍历+求连续区间满足某一条件的这种问题,而且数据规模比较大

P1102 A-B 数对

1-6二分做过。

package _1_6;import java.io.*;
import java.util.Arrays;public class P1102 {private static StreamTokenizer in;private static PrintWriter out;private static long[] nums;private static long c;private static int n;public static void main(String[] args) throws IOException {in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));out = new PrintWriter(System.out);in.nextToken();n = (int) in.nval;in.nextToken();c = (long) in.nval;nums = new long[n];for (int i = 0; i < n; i++) {in.nextToken();nums[i] = (long) in.nval;}// 先排序Arrays.sort(nums);// algo 双指针long count = 0;int l = 0, r = 0;for (int i = 0; i < n; i++) {// 找到第一个nums[l]-nums[i]>=c,nums[r]-nums[i]>c,则l~r-1区间就是-nums[i]==cwhile (l < n && nums[l] - nums[i] < c) l++;while (r < n && nums[r] - nums[i] <= c) r++;// 如果l==n则表示找不到对应值if (l < n && nums[l] - nums[i] == c && r >= 1 && nums[r - 1] - nums[i] == c)count += r - l;}out.println(count);out.flush();out.close();}
}

P1638 逛画展

看着n的数量级,只能O(n)时间才AC,可以用双指针

package _2_2;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;public class P1638 {private static StreamTokenizer in;public static void main(String[] args) throws IOException {in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));int n = nextInt();int m = nextInt();int[] draws = new int[n + 1];// visited存当前范围包含了画师i的次数int[] visited = new int[m + 1];// cnt表示包含了画师的种数int cnt = 0;for (int i = 1; i <= n; i++) {draws[i] = nextInt();}// algo 双指针int l, r;l = 1;r = l - 1;// r右移一直到包含所有画师while (cnt != m && r <= n - 1) {r++;// 如果当前这幅画的画师没有被包含,那就加入if (visited[draws[r]] == 0) {cnt++;}visited[draws[r]] += 1;}// 去除左端重复的画师while (r - l + 1 >= m && visited[draws[l]] > 1) {visited[draws[l]]--;l++;}if (r - l + 1 == m) {System.out.printf("%d %d", l, r);return;}// 此时lr区间已经满足了条件包含所有画师的目前最短,但是也有可能后续还有更短的区间// 继续r+1,每次去除左端重复,如果区间更小了那就更新(如果相同不更新,因为多组解得l更小的)int minl = l, minr = r;while (r <= n - 1) {r++;visited[draws[r]] += 1;// 去除左端重复的画师while (r - l + 1 >= m && visited[draws[l]] > 1) {visited[draws[l]]--;l++;}// 更新更短的区间if (r - l < minr - minl) {minr = r;minl = l;}}System.out.printf("%d %d", minl, minr);}public static int nextInt() throws IOException {in.nextToken();return (int) in.nval;}
}

空间换时间

(题外话:之前不是有一道异或题吗,4Mb的空间Java根本AC不了)

P7072 [CSP-J2020] 直播获奖

首先想到的就是每次读入选手的成绩后排序,然后求出前w%个人的最低成绩。

Java的Arrays.sort用了一个TimSort,时间复杂度是O(ologn)。不过注释说如有部分排序了,那这个算法的实际时间远低于nlgn。

不过这样的话,这个朴素的写法的时间复杂度是O(n2logn),可以过104的数量级,但是后面三个105就TLE。

这里有个注意的点,Arrays.sort(T[],start,end,Comparator)这里的数组要用包装类的

package _2_2;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.Comparator;public class P7072 {private static StreamTokenizer in;private static PrintWriter out;public static void main(String[] args) throws IOException {in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));out = new PrintWriter(System.out);int n = nextInt();double w = nextInt() * 0.01;Integer[] scores = new Integer[n + 1];for (int i = 1; i <= n; i++) {// 当前i个人,前w%就是i*0.01*w个人,然后再获得最后一个人的成绩scores[i] = nextInt();// 降序排序,这里要用Integer包装类,所以也可以选择从后面往前面选Arrays.sort(scores, 1, i + 1, Comparator.reverseOrder());int t = (int) (i * w);if (t < 1) {t = 1;}out.printf("%d ", scores[t]);}out.flush();out.close();}public static int nextInt() throws IOException {in.nextToken();return (int) in.nval;}
}

关键点在排序时间上,可以使用时间复杂度为O(n)的桶排序:点题用空间换时间,1-2曾做到过一道桶排序。因为桶排序不是比较排序,所以不受O(ologn)的限制(比较排序这个时间复杂度是最优的了)。还有一点,题中的值范围<=600,所以空间也不用开很大,也可以想到桶排序。

package _2_2;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.Comparator;public class P7072 {private static StreamTokenizer in;private static PrintWriter out;public static void main(String[] args) throws IOException {in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));out = new PrintWriter(System.out);int n = nextInt();double w = nextInt() * 0.01;int[] scores = new int[605];for (int i = 1; i <= n; i++) {scores[nextInt()]++;// 当前i个人,前w%就是i*0.01*w个人,然后再获得最后一个人的成绩int t = (int) (i * w);if (t < 1) {t = 1;}// 找第t个人的分数(注意降序)int j;for (j = 604; j >= 0; j--) {if (scores[j] > 0) {// 这里会对scores操作,所以一次性-去,这样就不会改变scores了,反正判断也是t<=0t -= scores[j];}// 因为可能重分,所以t<=0的时候也算找到分数线if (t <= 0) {out.printf("%d ", j);break;}}}out.flush();out.close();}public static int nextInt() throws IOException {in.nextToken();return (int) in.nval;}
}

P2671 [NOIP2015 普及组] 求和

按照颜色分组想到了,把等式移相一下没想到。

单调栈

P2866 [USACO06NOV] Bad Hair Day S

什么是单调栈?单调栈(C/C++)-CSDN博客

就是栈里维护一个单调序列:可解题型如下,往一边找第一个比自身大/小的值

image-20240315121219633

以这道题为例,都是往右边第一个>=自身(条件)的数,所以从后往前遍历。

  1. 如果栈空,直接保存结果-1;
  2. 如果栈顶元素满足条件(>=自身),直接保存结果为栈顶元素(此题要的是下标,比较的时候用的是下标对应值);
  3. 如果栈顶元素不满足条件(<自身),则出栈直到情况1或2。
package _2_2;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.LinkedList;public class P2866 {private static StreamTokenizer in;private static int n;private static int[] hs;private static LinkedList<Integer> stack;public static void main(String[] args) throws IOException {in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));n = nextInt();hs = new int[n + 1];stack = new LinkedList<Integer>();for (int i = 1; i <= n; i++) {hs[i] = nextInt();}long cnt = 0;// 注意从后往前遍历for (int i = n; i >= 0; i--) {int t = findHeigher(i);if (t == -1) {cnt += n - i;} else {cnt += t - i - 1;}}System.out.println(cnt);}// algo 单调栈public static int findHeigher(int i) {// 弹出栈顶,直到满足情况1或2,返回结果(注意栈里存的是下标),压入当前值while (stack.size() > 0 && hs[stack.getFirst()] < hs[i]) {stack.removeFirst();}// 栈空,返回结果-1,压入当前值if (stack.size() == 0) {stack.addFirst(i);return -1;} else {// 这里要先获取栈顶元素,再压栈int t = stack.getFirst();stack.addFirst(i);return t;}}public static int nextInt() throws IOException {in.nextToken();return (int) in.nval;}
}

单调队列

P1886 滑动窗口 /【模板】单调队列

什么是单调队列?单调队列 - Lan_Sky - 博客园 (cnblogs.com)、[数据结构]–单调队列-CSDN博客

单调队列通常解决动态小区间中寻找极值问题

  • 动态区间找最小值,使用单调递增序列,队首就是最小值;
  • 动态区间找最大值,使用单调递减序列,队首就是最大值;

中间操作都是类似的,例如找最小值,要维护单调递增序列

image-20240315124842254

如果当前遍历到的值违反了队列的单调要求,那么就要把元素从队尾出队,每次都要把新元素从队尾入队。

如果当前队列中的元素的下标已经不在滑动窗口内了,则这个值从队首出队

为什么最小值是维护单调递增序列,可以见2。

  • 因为窗口在滑动,所以即使目前这个值不是最小的,但是窗口滑动之后他有可能成为最小的(因为他被放在了极小的后面,窗口又向右边滑动),所以要存起来。
  • 但是如果当前这个值比队列一些元素都小,放入队列后即使找最小值也已经不可能再找队首那部分的值了(都有更小的了),所以前面的要出队。
package _2_2;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.LinkedList;public class P1886 {private static StreamTokenizer in;private static PrintWriter out;private static LinkedList<Integer> queue;public static void main(String[] args) throws IOException {in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));out = new PrintWriter(System.out);int n = nextInt();int k = nextInt();int[] num = new int[n + 1];for (int i = 1; i <= n; i++) {num[i] = nextInt();}// algo 单调队列queue = new LinkedList<Integer>();// 求最小值,维护递增队列for (int i = 1; i <= n; i++) {// 把队首部分,不在滑动窗口内的值去掉,这里i属于窗口右边界:窗口部分i-k+1~iwhile (queue.size() > 0 && queue.getFirst() < (i - k + 1)) {queue.removeFirst();}// 从队尾开始维护队列单调递增while (queue.size() > 0 && num[queue.getLast()] > num[i]) {queue.removeLast();}// 入队queue.add(i);// 输出当前最值,注意右边界i从k开始才算一个完整窗口if (i >= k) {out.printf("%d ", num[queue.getFirst()]);}}out.println();queue.clear();// 求最大值,维护递减队列for (int i = 1; i <= n; i++) {// 把队首部分,不在滑动窗口内的值去掉,这里i属于窗口右边界:窗口部分i-k+1~iwhile (queue.size() > 0 && queue.getFirst() < (i - k + 1)) {queue.removeFirst();}// 从队尾开始维护队列单调递减while (queue.size() > 0 && num[queue.getLast()] < num[i]) {queue.removeLast();}// 入队queue.add(i);// 输出当前最值,注意右边界i从k开始才算一个完整窗口if (i >= k) {out.printf("%d ", num[queue.getFirst()]);}}out.flush();out.close();}public static int nextInt() throws IOException {in.nextToken();return (int) in.nval;}
}

60%AC,有几个TLE,那换静态数组?

package _2_2;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.LinkedList;public class P1886 {private static StreamTokenizer in;private static PrintWriter out;private static LinkedList<Integer> queue;private static int n;private static int k;private static int[] nums;public static void main(String[] args) throws IOException {in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));out = new PrintWriter(System.out);n = nextInt();k = nextInt();nums = new int[n + 1];for (int i = 1; i <= n; i++) {nums[i] = nextInt();}fun2();out.flush();out.close();}// algo 单调队列:静态数组版public static void fun2() {int[] queue = new int[n + 1];// 双指针指向队首尾,此时size=tail-head+1,所以表示空即tail+1=headint head = 1, tail = 0;// 求最小值,维护递增队列for (int i = 1; i <= n; i++) {// 把队首部分,不在滑动窗口内的值去掉,这里i属于窗口右边界:窗口部分i-k+1~iwhile (tail - head + 1 > 0 && queue[head] < (i - k + 1)) {head++;}// 从队尾开始维护队列单调递增while (tail - head + 1 > 0 && nums[queue[tail]] > nums[i]) {tail--;}// 入队queue[++tail] = i;// 输出当前最值,注意右边界i从k开始才算一个完整窗口if (i >= k) {out.printf("%d ", nums[queue[head]]);}}out.println();queue = new int[n + 1];head = 1;tail = 0;// 求最大值,维护递减队列for (int i = 1; i <= n; i++) {// 把队首部分,不在滑动窗口内的值去掉,这里i属于窗口右边界:窗口部分i-k+1~iwhile (tail - head + 1 > 0 && queue[head] < (i - k + 1)) {head++;}// 从队尾开始维护队列单调递增while (tail - head + 1 > 0 && nums[queue[tail]] < nums[i]) {tail--;}// 入队queue[++tail] = i;// 输出当前最值,注意右边界i从k开始才算一个完整窗口if (i >= k) {out.printf("%d ", nums[queue[head]]);}}}public static int nextInt() throws IOException {in.nextToken();return (int) in.nval;}
}

就多了一个AC

区间最值

P4147 玉蟾宫

P1950 长方形

P2216 [HAOI2007] 理想的正方形

都是提高题

浅谈用极大化思想解决最大子矩形问题-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/790645.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ES9学习 -- 对象的剩余参数与扩展运算符 / 正则扩展 / Promise.finally / 异步迭代

文章目录 1. 对象的剩余参数与扩展运算符1.1 对象的剩余参数1.2 扩展运算符 2. 正则扩展3. Promise.finally4. 异步迭代4.1 同步遍历器的问题4.2 异步遍历器使用 1. 对象的剩余参数与扩展运算符 1.1 对象的剩余参数 let obj { name:"kerwin", age:100, location:&…

推理端框架简介 高通SNPE 神经网络处理引擎 阿里巴巴 MNN 腾讯 FeatherCNN 端侧推理引擎 卷积计算优化 卷积计算优化

高性能计算(High performance computing, 缩写HPC) 指通常使用很多处理器(作为单个机器的一部分) 或者某一集群中组织的几台计算机(作为单个计 算资源操作)的计算系统和环境。 有许多类型的HPC 系统,其范围从标准计算机的大型集群,到高度专用的硬件。 大多数基于集群的H…

MVCC详细总结

简介 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;是一种多版本并发控制机制&#xff0c;主要用于数据库管理系统中&#xff0c;实现对数据库的并发访问。在编程语言中&#xff0c;MVCC可以实现事务内存。 MVCC的特点是读不加锁&#xff0c;读写不冲突。MVC…

(表征学习论文阅读)FINITE SCALAR QUANTIZATION: VQ-VAE MADE SIMPLE

1. 前言 向量量化&#xff08;Vector Quantization&#xff09;或称为矢量量化最早在1984年由Gray提出&#xff0c;主要应用于数据压缩、检索领域&#xff0c;具体的阐述可以参考我写的另一篇关于VQ算法的文章。随着基于神经网络的离散表征学习模型的兴起&#xff0c;VQ技术也…

二维动画制作软件 Animate 2024 for mac激活版

Animate 2024 for Mac是一款功能强大的二维动画制作软件&#xff0c;专为Mac用户打造。它提供了丰富的动画编辑功能&#xff0c;使用户能够轻松创建出生动逼真的动画作品。无论是短片、广告还是游戏等应用领域&#xff0c;Animate 2024都能发挥出出色的表现。 软件下载&#xf…

部署k8s客户端,及docker私仓部署

1.部署一个docker私仓 mkdir /opt/docker/registry #配置仓库密码 mkdir /opt/docker/auth cd /opt/docker/auth htpasswd -Bbn admin admin > htpasswd#运行docker私仓服务&#xff0c;下面端口5000:5000 前面的5000对应本机端口可以自定义 docker run -itd \ -v /opt/d…

【Layui】------ layui实现table表格拖拽行、列位置的示例代码

一、完整的示例代码&#xff1a;&#xff08;请使用layui v2.8.3的版本&#xff09;看懂就能用、不要照搬、照搬会出错误、拷贝重要代码改改符合你自己的需求。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><…

MapReduce [OSDI‘04] 论文阅读笔记

原论文&#xff1a;MapReduce: Simplified Data Processing on Large Clusters (OSDI’04) 1. Map and Reduce Map&#xff1a;处理键值对&#xff0c;生成一组中间键值对Reduce&#xff1a;合并与同一中间键相关的所有中间值process overview&#xff1a;分割输入数据&#x…

DSO9254A安捷伦DSO9254A示波器

181/2461/8938产品概述&#xff1a; 安捷伦DSO9254A的带宽为2.5 GHz&#xff0c;配备15英寸XGA液晶显示屏&#xff0c;采用静音封装&#xff0c;厚度仅为9英寸&#xff08;23厘米&#xff09;&#xff0c;重量仅为26磅&#xff08;11.8千克&#xff09;。DSO9254A集成了一个功…

UE4_自定义反射和折射和法线图

UE4 自定义反射和折射和法线图 2020-05-22 09:36 将ReflectionVector和反射图像进行ViewAlignedReflection,输出的textrue和相机位置CameraPosition的onePlus进行Dot点乘之后乘以一个float系数反射度&#xff0c;输出给固有色&#xff0c;就有反射效果了。球型反射。 折射&…

Coze工作流介绍(一)

Coze工作流介绍 工作流支持通过可视化的方式&#xff0c;对插件、大语言模型、代码块等功能进行组合&#xff0c;从而实现复杂、稳定的业务流程编排&#xff0c;例如旅行规划、报告分析等。 当目标任务场景包含较多的步骤&#xff0c;且对输出结果的准确性、格式有严格要求时…

JAVAEE—Callable接口,ReentrantLock,synchronized的工作过程

文章目录 Callable接口的用法Callable与FutureTask类 加锁的工作过程什么是偏向锁呢&#xff1f;举个例子 轻量级锁重量级锁 ReentrantLockReentrantLock 的用法: Callable接口的用法 Callable 是一个 interface . 相当于把线程封装了一个 “返回值”. 方便程序猿借助多线程的…

Ubuntu20.04使用Neo4j导入CSV数据可视化知识图谱

1.安装JDK&#xff08; Ubuntu20.04 JDK11&#xff09; sudo apt-get install openjdk-11-jdk -y java -version which java ls -l /usr/bin/java ls -l /etc/alternatives/java ls -l /usr/lib/jvm/java-11-openjdk-amd64/bin/java确认安装路径为/usr/lib/jvm/java-11-openjd…

Celery的任务流

Celery的任务流 在之前调用任务的时候只是使用delay()和apply_async()方法。但是有时我们并不想简单的执行单个异步任务&#xff0c;比如说需要将某个异步任务的结果作为另一个异步任务的参数或者需要将多个异步任务并行执行&#xff0c;返回一组返回值&#xff0c;为了实现此…

STL是什么?如何理解STL?

文章目录 1. 什么是STL2. STL的版本3. STL的六大组件4. 如何学习STL5.STL的缺陷 1. 什么是STL STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且是一个包罗数据结构与算法的软件框架。 2. …

OpenHarmony实战开发-使用一次开发多端部署实现一多设置典型页面

介绍 本示例展示了设置应用的典型页面&#xff0c;其在小窗口和大窗口有不同的显示效果&#xff0c;体现一次开发、多端部署的能力。 1.本示例使用一次开发多端部署中介绍的自适应布局能力和响应式布局能力进行多设备&#xff08;或多窗口尺寸&#xff09;适配&#xff0c;保…

WebGIS 之 vue3+vite+ceisum

1.项目搭建node版本在16以上 1.1创建项目 npm create vite 项目名 1.2选择框架 vuejavaScript 1.3进入项目安装依赖 cd 项目名 npm install 1.4安装cesium依赖 pnpm i cesium vite-plugin-cesium 1.5修改vite.config.js文件 import { defineConfig } from vite import vue fr…

RK3568 RTC驱动实验

RK3568 RTC驱动实验 1. RTC简介 ​ RTC 也就是实时时钟&#xff0c;用于记录当前系统时间&#xff0c;对于 Linux 系统而言时间是非常重要的&#xff0c;使用 Linux 设备的时候也需要查看时间。RTC是Linux的时间系统。 ​ RTC 设备驱动是一个标准的字符设备驱动&#xff0c;…

基于Python的微博旅游情感分析、微博舆论可视化系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Python网络爬虫(三):Selenium--以携程酒店为例

1 Selenium简介 Selenium是一个用于网站应用程序自动化的工具&#xff0c;它可以直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。它相当于一个机器人&#xff0c;可以模拟人类在浏览器上的一些行为&#xff0c;比如输入文本、点击、回车等。Selenium支持多种浏览器&…