牛客周赛 Round 21 解题报告 | 珂学家 | 堆栈的妙用


前言

alt


整体评价

从A题中的Baidu, 可以猜到这场有几道题来自于百度校招。

其实B题有点意思,如果把十字星的范围放大,那就可以成为一个hard题。

D题也挺意思的,大概有两种思路,一种是从左到右枚举右端点,增量累加,一种是贡献思路。


欢迎关注

珂朵莉 牛客周赛专栏

珂朵莉 牛客小白月赛专栏


A. 小红的Baidu

字符串s,重排后,可以等价于“Baidu”

思路, 最小化表达式

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;public class Main {// Java 对 char数组,比较特殊static String expression(String s) {return s.chars().sorted().mapToObj(x -> "" + ((char)x)).reduce("", (a, b) -> a + b);}public static void main(String[] args) {// Baidu的最小表达式String p1 = expression("Baidu");Scanner sc = new Scanner(new BufferedInputStream(System.in));int t = sc.nextInt();while (t-- > 0) {String s = sc.next();String p2 = expression(s);if (p1.equals(p2)) {System.out.println("Yes");} else {System.out.println("No");}}}}

B. 小红盖章

因为十字星的影响范围小,所以可以正向模拟即可。

但是如果这题十字星的范围很大,那又该如何求解呢?

这题,可以用逆向思路,即后续操作的优先级最大,后续操作会覆盖前面的。

但是仅有逆向思维是不够的,还需要对范围遍历进行优化,这需要借助数据结构。

  • 构建横向W个链式并查集,纵向H个链式并查集,根据逆序优先,把遍历的代价(4K)降到均摊O(1)
  • treeset, 均摊代价为 O ( l o g n ) O(log n) O(logn)

这边还是正向解法

import java.io.*;
import java.util.*;public class Main {static int[][] dirs = new int[][] {{-1, 0}, {-2, 0}, {1, 0}, {2, 0},{0, -1}, {0, -2}, {0, 1}, {0, 2}};public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));int h = sc.nextInt(), w = sc.nextInt();int k = sc.nextInt();char[][] grid = new char[h][w];for (int i = 0; i < h; i++) {Arrays.fill(grid[i], '.');}// 正向操作for (int i = 0; i < k; i++) {int y = sc.nextInt() - 1, x = sc.nextInt() - 1;char g = sc.next().charAt(0);grid[y][x] = g;for (int j = 0; j < dirs.length; j++) {int y0 = y + dirs[j][0];int x0 = x + dirs[j][1];if (y0 >= 0 && y0 < h && x0 >= 0 && x0 < w) {grid[y0][x0] = g;}}}for (int i = 0; i < h; i++) {System.out.println(new String(grid[i]));}}}

逆序+链式并查集

import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.Scanner;public class Main {// 链式并查集static class Dsu {int n;int[] arr;public Dsu(int n) {this.n = n + 1;this.arr = new int[n + 2];Arrays.fill(arr, -1);}int leader(int u) {if (arr[u] == -1) return u;return arr[u] = leader(arr[u]);}// 向右合并void merge(int u) {int ai = leader(u);int bi = leader(ai + 1);arr[ai] = bi;}}static class Tx {int x, y;char s;public Tx(int x, int y, char s) {this.x = x;this.y = y;this.s = s;}}public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));int h = sc.nextInt(), w = sc.nextInt();int k = sc.nextInt();char[][] grid = new char[h][w];for (int i = 0; i < h; i++) {Arrays.fill(grid[i], '.');}Dsu[] rows = new Dsu[h];Arrays.setAll(rows, x -> new Dsu(w));Dsu[] cols = new Dsu[w];Arrays.setAll(cols, x -> new Dsu(h));Tx[] ops = new Tx[k];for (int i = 0; i < k; i++) {int x = sc.nextInt() - 1, y = sc.nextInt() - 1;char g = sc.next().charAt(0);ops[i] = new Tx(x, y, g);}int E = 2; // 十字的边长// 逆序for (int i = k - 1; i >= 0; i--) {Tx op = ops[i];// 水平方向Dsu row = rows[op.x];int s = Math.max(op.y - E, 0);int e = Math.min(op.y + E, w - 1);while (true) {int y0 = row.leader(s);if (y0 > e) break;if (grid[op.x][y0] == '.') {grid[op.x][y0] = op.s;}row.merge(y0);}// 垂直方向Dsu col = cols[op.y];s = Math.max(op.x - E, 0);e = Math.min(op.x + E, h - 1);while (true) {int x0 = col.leader(s);if (x0 > e) break;if (grid[x0][op.y] == '.') {grid[x0][op.y] = op.s;}col.merge(x0);}}for (int i = 0; i < h; i++) {System.out.println(new String(grid[i]));}}}

C. 小红的数组修改

枚举每个位子被修改,然后计算在限制内,可以修改几种方式,能满足需求。

这边有3个限制

  • 被改变的数,必须小于等于p
  • 必须改变,不能为原先的值
  • 改变后,数组和为k的倍数

假设数组累加和S

则改变后

S - arr[i] + y = k * x

取模变换

(arr[i] - S) mod k = y mod k, 且0 < y <= p, y != arr[i]

求得,r = (arr[i] - S) mod k, r为非负整数

转化为 y = k * t + r, 此时 0 < y <= p, 求t的非整数解个数

因为y<=p, 因此个数为 基本盘为 (p - r) / k

但是这里面有两个边界

  • 如果r>0, 则修改方案需要额外 +1
  • 如果arr[i] % k == r, 则需要额外 -1
import java.io.*;
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));int n = sc.nextInt();int p = sc.nextInt();int x = sc.nextInt();long acc = 0;long[] arr = new long[n];for (int i = 0; i < n; i++) {arr[i] = sc.nextLong();acc += arr[i];}// 枚举long res = 0;for (int i = 0; i < n; i++) {long left = (acc - arr[i]) % x;// r为对应的同余long r = (left == 0) ? 0 : (x - left);if (p >= r) {res += (p - r) / x;if (r > 0) res++; // 需要补上1个// 需要去除相等的情况if (arr[i] <= p && arr[i] % x == r) res--;}}System.out.println(res);}}

D. 括号匹配问题

大致有两种思路,但无一例外都借助stack来实现。

以往做括号相关的题时,往往会引入stack来实现,这次也是如此。

方法1:递推函数

S(i) 为 以i节点为右端点的所有子区间的()配对数

则S(i+1) 和 S(i) 的递进关系如何维护?

  • 如果str[i+1]为’(’

那么 S(i+1)=S(i), 即配对数完全复制,但是没有新增加

  • 如果str[i+1]为’)‘

那这个’)', 可与左侧多余的’(‘构建一个新的配对关系,那具体能贡献多少个新增呢? 这又如何维护呢?

其实可以手玩一下,就能发现,在i处增加一个’(', 相当于stack push(i+1)个,而消耗匹配一个,相当于stack pop栈顶。

因此 S(i + 1) = S(i) + 2 * stack.pop()

而最终的结果为 ∑ S ( i ) \sum S(i) S(i)

import java.io.BufferedInputStream;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));char[] str = sc.next().toCharArray();int n = str.length;long res = 0;long s = 0;Deque<Integer> stack = new ArrayDeque<>();// 可能要数据结构辅助for (int i = 0; i < n; i++) {char c = str[i];if (c == '(') {stack.push((i + 1));} else if (c == ')') {if (!stack.isEmpty()) {int v = stack.pop();s += 2l * v;}}res += s;}System.out.println(res);}}

方法2:贡献法

看了下前排大佬,基本都是贡献法

就是找到一个新()匹配, 其可以在多少个区间中重复贡献。

也是基于stack

匹配的时候, ∑ s t a c k . p o p ( ) ∗ ( n − i ) \sum stack.pop() * (n - i) stack.pop()(ni)

import java.io.BufferedInputStream;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));char[] str = sc.next().toCharArray();int n = str.length;long res = 0;Deque<Integer> stack = new ArrayDeque<>();// 可能要数据结构辅助for (int i = 0; i < n; i++) {char c = str[i];if (c == '(') {stack.push((i + 1));} else if (c == ')') {if (!stack.isEmpty()) {int v = stack.pop();res += 2l * v * (n - i);
;               }}}System.out.println(res);}}

写在最后

alt

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

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

相关文章

【C/C++】C/C++编程——为什么学习 C++?

当提到C的时候&#xff0c;很多人会觉得语法复杂、学习曲线陡峭&#xff0c;并且好像与C语言还有点"纠缠不清"。尽管如此&#xff0c;C仍然是当今世界上最受欢迎和最有影响力的编程语言之一。特别是在当今快速发展的人工智能&#xff08;AI&#xff09;领域&#xff…

利用GPU加速自定义风格图像生成-利用GPU加速结合了ControlNet/ Lora的Stable Diffusion XL

点击链接完成注册&#xff0c;参加本次在线研讨会 https://www.nvidia.cn/webinars/sessions/?session_id240124-31319 随着AI技术的发展, 数字内容创建业务也变得越来越火热。生成式AI模型的发布, 让我们看到了人工智能在各行各业的潜力。您只需要用语言简单描述自己希望看…

黑马苍穹外卖学习Day10

文章目录 Spring Task介绍cron表达式入门案例 订单状态定时处理需求分析代码开发功能测试 WebSocket介绍入门案例 来单提醒需求分析代码开发 客户催单需求分析代码开发 Spring Task 介绍 cron表达式 入门案例 订单状态定时处理 需求分析 代码开发 新建一个task包里面编写代码…

REVIT二次开发批量编号

步骤1 步骤2 步骤3 实现代码using System; using System.Collections.Generic; using System.Linq; using Syste

《Python数据分析技术栈》第03章 03 可视化各级数据(Visualizing various levels of data)

03 可视化各级数据&#xff08;Visualizing various levels of data&#xff09; 《Python数据分析技术栈》第03章 03 可视化各级数据&#xff08;Visualizing various levels of data&#xff09; Whenever you need to analyze data, first understand if the data is stru…

C++三剑客之std::variant(二):深入剖析

目录 1.概述 2.辅助类介绍 2.1.std::negation 2.2.std::conjunction 2.3.std::is_destructible 2.4.std::is_object 2.5.is_default_constructible 2.6.std::is_trivially_destructible 2.7.std::in_place_type和std::in_place_index 3.原理分析 3.1.存储分析 3.2.…

【蓝桥杯EDA设计与开发】资料汇总以及立创EDA及PCB相关技术资料汇总(持续更新)

[18/01/2024]&#xff1a;目前为了准备蓝桥杯做一些资料贴&#xff0c;于是写下这一篇博客。 各种资料均来源于网络以及部分书籍、手册等文档&#xff0c;参考不保证其准确性。 如果在准备蓝桥杯&#xff0c;可与我私信共同学习&#xff01;&#xff01;&#xff01;&#xf…

SCTP, TCP, UDP, IP, ICMP都在哪一层?(TCP/IP网络通信协议学习)

TCP/IP网络通信协议最早是由罗伯特卡恩&#xff08;Robert E. Kahn&#xff09;和文顿瑟夫&#xff08;Vinton G. Cerf&#xff09;于1972年提出的&#xff0c;它是一个实际的协议栈。 OSI七层网络通信协议最早是由国际标准化组织&#xff08;ISO&#xff09;于1977年提出的&am…

0基础转行做软件测试?一文教小白拿到初级岗位offer?

我认为入门软件测试需要四个方面的知识or技能&#xff0c;它们是&#xff1a;业务知识、职业素养、基础知识、技术知识。 职业素养是一切的根基&#xff0c;因为人在职场就必须拥有必要的职业素养&#xff0c;软件测试工程师也不例外。基础知识和技术知识是两大支柱&#xff0…

Kubernetes网络模型概述

Kubernetes网络模型设计的一个基础原则是&#xff1a;每个Pod都拥有一个独立的IP地址&#xff0c;并假定所有Pod都在一个可以直接连通的、扁平的网络空间中。所以不管这些Pod是否运行在同一个Node中&#xff0c;都要求它们可以直接通过对方的IP进行访问。由于Kubernetes的网络模…

分布式锁的产生以及使用

日常开发中&#xff0c;针对一些需要锁定资源的操作&#xff0c;例如商城的订单超卖问题、订单重复提交问题等。 都是为了解决在资源有限的情况限制客户端的访问&#xff0c;对应的是限流。 单节点锁问题 目前针对这种锁资源的情况采取的往往是互斥锁&#xff0c;例如 java 里…

顶顶通用户申请和安装 空号识别 模块流程

一、申请 空号识别 授权 打开网址&#xff1a;http://my.ddrj.com&#xff0c;注册并登录。 点击“我的授权” -> “申请授权” &#xff08;根据负责人的要求选择“在线”或是“离线”&#xff09;。 找到名称为空号识别的授权并点击“加号”图标打开授权&#xff0c;然…

Uni-App三甲医院、医保定点三甲医院在线预约挂号系统源码

医院在线预约挂号系统是一种方便患者预约挂号的系统&#xff0c;患者可以通过该系统进行预约挂号&#xff0c;省去了到医院现场排队等待的时间&#xff0c;提高了就诊效率。随着医院信息化水平的不断发展&#xff0c;医院在线预约挂号管理系统已成为医院管理中不可或缺的一部分…

SQL-窗口函数

什么是窗口函数 可以像聚合函数一样对一组数据进行分析并返回结果&#xff0c;二者的不同之处在于&#xff0c;窗口函数不是将一组数据汇总成单个结果&#xff0c;而是为每一行数据都返回一个结果。 窗口函数组成部分 1.创建数据分区 窗口函数OVER子句中的PARTITION BY选项用…

大师学SwiftUI第6章 - 声明式用户界面 Part 3

安全域视图 SwiftUI还内置了创建安全文本框的视图。这一视图会把用户输入的字符替换成点以及隐藏敏感信息&#xff0c;比如密码。 SecureField(String, text: Binding)&#xff1a;该初始化方法创建一个安全输入框。第一个参数定义占位文本&#xff0c;​​text​​参数为存储…

leetcode 013二维区域和检索---矩阵不可变

给定一个二维矩阵 matrix&#xff0c;以下类型的多个请求&#xff1a; 计算其子矩形范围内元素的总和&#xff0c;该子矩阵的左上角为 (row1, col1) &#xff0c;右下角为 (row2, col2) 。 实现 NumMatrix 类&#xff1a; NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进…

Quartus II使用小技巧

工程结构&#xff1a; 在建立完某项设计的文件后&#xff0c;依次在其里面新建四个文件夹&#xff0c;分别为&#xff1a;rtl、qprj、msim、doc。 rtl文件夹用于存放设计的源文件。 doc文件夹用于存放设计的一些文档性的资料。 qprj文件夹用于存放quaruts 工程以及quartus生…

Git入门详细教程

一、Git概述&#x1f387; Git官网 Git是一个开源的分布式版本控制系统&#xff0c;用于跟踪文件的变化和协作开发。它允许多个开发者在同一项目中共同工作&#xff0c;并能够有效地管理代码的版本和历史记录。Git可以帮助开发团队更好地协作&#xff0c;追踪代码变更&#xf…

记一次多平台免杀PHP木马的制作过程

注意&#xff1a;本文转载自本作者稀土掘金博客 博客地址&#xff1a; 御坂19008号 的个人主页 - 动态 - 掘金 文章目录 前言声明绕过情况使用方法运行环境绕过点介绍技术原理讲解变量传值覆盖模块代码执行阻断模块InazumaPuzzle程序锁定器PerlinNoise危险函数生成与执行类构造…

Android 基础技术——addView 流程

笔者希望做一个系列&#xff0c;整理 Android 基础技术&#xff0c;本章是关于 addView 在了解 addView 流程之前&#xff0c;先回答下以下几个问题&#xff1a; PhoneWindow是什么时候创建的&#xff1f; DectorView 是什么&#xff1f; DectorView 是什么时候创建的&#xf…