牛客周赛 Round 22 解题报告 | 珂学家 | 思维构造 + 最小生成树


前言

alt


整体评价

C题这个构造题挺好的,赛中把-1写成No, 直接整不会了,T_T.

D题是一道很裸的最小生成树题,只需要一个小小的逆向思维,把删除操作转换为构建过程。


欢迎关注

珂朵莉 牛客周赛专栏

珂朵莉 牛客小白月赛专栏


A. 小红的漂亮串

数据规模较小,直接暴力匹配即可,当然也可以使用API。

import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        String s = sc.next();

        int cnt = 0;
        int pos = 0;
        while (cnt < 2 && (pos = s.indexOf("red", pos)) != -1) {
            pos += 3;
            cnt++;
        }
        System.out.println(cnt >= 2 ? "Yes": "No");
    }

}
s = input()

p = 0
cnt = 0
# find 和 index的区别
while cnt < 2 and s.find("red", p) != -1:
    cnt += 1
    p = s.find("red", p) + 1
    
print ("Yes" if cnt >= 2 else "No")


B. 小红的偶子串

好像滑窗贪心是错误的

引入dp[i + 1], 表示以i结尾,且是偶数位的最长子串(为了处理方便,漂移了一位)

  • dp[i + 1] = dp[i - 1] + 2, str[i] == str[i - 1]

  • dp[i + 1] = 0, str[i] != str[i - 1]

import java.io.BufferedInputStream;
import java.util.Arrays;
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;

        int res = 0;
        int[] dp = new int[n + 1];
        for (int i = 1; i < n; i++) {
            if (str[i] == str[i - 1]) {
                dp[i + 1] = dp[i - 1] + 2;
            }
            res = Math.max(res, dp[i + 1]);
        }

        System.out.println(res);

    }

}
s = input()

n = len(s)
dp = [0] * (n + 1)

dp[0] = 0
for i in range(0, n - 1):
    if s[i] == s[i + 1]:
        dp[i + 2] = max(dp[i + 2], dp[i] + 2)

print (max(dp))

C. 小红的数组构造

首先可以排除掉不可能的情况

  • 1~n的累加和 > x
  • n > k

然后想如何构造这个神奇的数组呢?

可以先安排,1~n填充,即arr[i] = i

那这样还剩余

left = x - (n+1)*n/2

那如何处理这个剩余的部分呢?

其实可以对n进行乘除

  • d = left / n
  • r = left % n

把d赋值给每个元素,然后r这个尾巴相当于给最后的r个元素额外+1

这样的构造数组,应该是理想上最满足要求的数组了。


题外话:

赛中也采用了,类似后悔堆的思路,即先填充1~n,然后多余的从大到小进行置换,可以过,但是没法证明。

import java.io.BufferedInputStream;
import java.util.Scanner;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        int n = sc.nextInt();
        long k = sc.nextLong(), x = sc.nextLong();

        long s = ((long)n) * (n + 1) / 2;
        if (s > x || n > k) {
            System.out.println(-1);
        } else {
            long[] arr = new long[n + 1];
            for (int i = 1; i <= n; i++) {
                arr[i] = i;
            }

            x -= s;
            long d = x / n;
            long v = x % n;

            for (int i = 1; i <= n; i++) {
                arr[i] += d;
                if (n - i < v) {
                    arr[i]++;
                }
            }

            // 对数组进行最后的check,保证每个元素都小于等于k
            boolean ok = true;
            for (int i = 1;i <= n; i++) {
                if (arr[i] > k) ok = false;
            }
            
            if (!ok) System.out.println("-1");
            else System.out.println(IntStream.range(1, n + 1).mapToObj(t -> String.valueOf(arr[t])).collect(Collectors.joining(" ")));
        }
    }

}

D. 小红的图上删边

逆向思维,把删除转换为重头构建树,那这样就变成求最小生成树的过程了。

这边采用 kruskal算法,借助并查集来实现最小生成树的构建。

这边需要额外计算边权,其实就是统计每个点的2,5的因子数

w(u, v) = min(cnt5(u) + cnt5(v), cnt2(u) + cnt2(v))

整体的时间复杂度为 O ( m l o g m ) O(mlogm) O(mlogm), 主要在排序这块

import java.io.BufferedInputStream;
import java.util.*;

public class Main {

    static class Dsu {
        int n;
        int[] arr;
        int[] gz;
        public Dsu(int n) {
            this.n = n;
            this.arr = new int[n + 1];
            this.gz = new int[n + 1];
            Arrays.fill(gz, 1);
        }

        int find(int u) {
            if (arr[u] == 0) return u;
            return arr[u] = find(arr[u]);
        }

        void union(int u, int v) {
            int ai = find(u), bi = find(v);
            if (ai != bi) {
                arr[ai] = bi;
                gz[bi] += gz[ai];
            }
        }

        int gSize(int u) {
            return gz[find(u)];
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));

        int n = sc.nextInt(), m = sc.nextInt();

        Dsu dsu = new Dsu(n);
        long[] ws = new long[n + 1];
        int[] cnt5 = new int[n + 1];
        int[] cnt2 = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            ws[i] = sc.nextLong();

            long v = ws[i];
            while (v % 5 == 0)  {
                cnt5[i]++;
                v /= 5;
            }
            while (v % 2 == 0)  {
                cnt2[i]++;
                v /= 2;
            }
        }

        long res = 0;
        List<int[]> edges = new ArrayList<>();
        for (int i = 0; i < m; i++) {
            int u = sc.nextInt(), v = sc.nextInt();
            int w = Math.min(cnt5[u] + cnt5[v], cnt2[u] + cnt2[v]);

            // 引入边权
            edges.add(new int[] {u, v, w});
            res += w;
        }

        // 按边权从小到大排序
        Collections.sort(edges, Comparator.comparing(x -> x[2]));
        long tmp = 0;
        for (int[] e: edges) {
            int u = e[0], v = e[1], w = e[2];
            if (dsu.find(u) != dsu.find(v)) {
                dsu.union(u, v);
                tmp += w;
                if (dsu.gSize(1) == n) {
                    break;
                }
            }
        }

        // 删边收益 = 总的权值 - 最小生成树的权值
        System.out.println(res - tmp);
    }

}
import heapq

class Dsu(object):
    
    def __init__(self, n: int):
        self.n = n 
        self.arr = [0] * (n + 1) # index-1
        self.group = n
        
    def find(self, u: int) -> int:
        if self.arr[u] == 0:
            return u
        self.arr[u] = self.find(self.arr[u])
        return self.arr[u]
    
    def union(self, u :int, v: int):
        a = self.find(u)
        b = self.find(v)
        if a != b:
            self.arr[a] = b
            self.group -= 1
            
    def groupNum(self) -> int:
        return self.group
            
            
n, m = list(map(int, input().split()))
arr = list(map(int, input().split())) 

# 逆向思维
cnt2 = [0] * (n + 1)
cnt5 = [0] * (n + 1)

for i in range(len(arr)):
    v = arr[i]
    while v % 2 == 0:
        v /= 2
        cnt2[i + 1] += 1
    while v % 5 == 0:
        v /= 5
        cnt5[i + 1] += 1

res = 0
edges = []
for i in range(m):
    u, v = list(map(int, input().split()))
    edges.append((min(cnt2[u] + cnt2[v], cnt5[u] + cnt5[v]), u, v))
    res += min(cnt2[u] + cnt2[v], cnt5[u] + cnt5[v])

dsu = Dsu(n)
heapq.heapify(edges)

while dsu.groupNum() > 1 and len(edges):
    row = heapq.heappop(edges)
    if dsu.find(row[1]) != dsu.find(row[2]):
        dsu.union(row[1], row[2])
        res -= row[0]

print (res)

写在最后

alt

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HTTP content-type内容类型的常见格式

本专栏是汇集了一些HTML常常被遗忘的知识&#xff0c;这里算是温故而知新&#xff0c;往往这些零碎的知识点&#xff0c;在你开发中能起到炸惊效果。我们每个人都没有过目不忘&#xff0c;过久不忘的本事&#xff0c;就让这一点点知识慢慢渗透你的脑海。 本专栏的风格是力求简洁…

概率论中的 50 个具有挑战性的问题 [第 6 部分]:Chuck-a-Luck

一、说明 我最近对与概率有关的问题产生了兴趣。我偶然读到了弗雷德里克莫斯特勒&#xff08;Frederick Mosteller&#xff09;的《概率论中的五十个具有挑战性的问题与解决方案》&#xff09;一书。我认为创建一个系列来讨论这些可能作为面试问题出现的迷人问题会很有趣。每篇…

OAuth2.0 四种授权方式讲解

一、OAuth2.0 的理解 OAuth2是一个开放的授权标准&#xff0c;允许第三方应用程序以安全可控的方式访问受保护的资源&#xff0c;而无需用户将用户名和密码信息与第三方应用程序共享。OAuth2被广泛应用于现代Web和移动应用程序开发中&#xff0c;可以简化应用程序与资源服务器之…

顺序表的基本操作(必学)

目录 线性表&#xff1a; 顺序表&#xff1a; 概念和结构&#xff1a; 动态顺序表常用操作实现&#xff1a; 头文件&#xff08;数组顺序表的声明&#xff09;&#xff1a; 各种基本操作总的声明&#xff1a; 顺序表的初始化&#xff1a; 顺序表的销毁 顺序表的打印 …

录屏软件哪个好用?全方位测评告诉你

随着数字技术的不断发展&#xff0c;录制屏幕的需求也越来越大。无论是制作教程、记录游戏过程&#xff0c;还是保存会议内容&#xff0c;一款好用的录屏软件都能让用户事半功倍。可是录屏软件哪个好用呢&#xff1f;在本文中&#xff0c;我们将介绍三款流行的录屏软件。通过详…

std::string在 Windows MSVC和Linux Gcc 中capacity容量扩容策略的分析和对比

1、capacity()作用 在std::string中&#xff0c;capacity()为当前string占用内存字符的长度&#xff0c;表示当前string的容量&#xff0c;可以理解为一个预分配制度&#xff0c;如果当前的string不断进行扩展操作&#xff0c;则不需要每次都进行内存上的分配&#xff0c;提高程…

iconify图标集离线使用方案简介

1.需求描述 前端项目&#xff0c;技术栈使用Vue3Element Plus&#xff0c;参考了ruoyi-vue-pro项目与vue-element-plus-admin项目&#xff0c;封装了一个Icon组件&#xff0c;图标使用的是iconify,项目部署在内网环境&#xff0c;不能连接互联网&#xff0c;需要部署一套iconi…

MAC鼠标中键的使用

MAC鼠标没有鼠标中键&#xff0c;于是在一些场景中用起来非常麻烦&#xff0c;这里介绍几种键盘快捷键鼠标左键实现中键功能的例子&#xff1a; 1&#xff09;在sublime text 或者pycharm等一些文本编辑器或IDE中实现中键修改一列数据中特定位置的值 FNOPT左键另外还有C4D&…

生存分析序章1——解析生存分析:探寻时间与事件的奥秘

写在开头 生存分析&#xff0c;作为统计学和生物学交汇的领域&#xff0c;旨在探究时间与事件之间的奥秘。这一领域的深入研究不仅在医学和生物学领域有着广泛的应用&#xff0c;同时在数据分析和数据挖掘中也发挥着关键作用。 1 基本概念 1.1 什么是生存分析 生存分析&…

STM32独立看门狗和窗口看门狗的区别

独立看门狗&#xff1a; 本质上是一个定时器&#xff0c;这个定时器有一个输出端&#xff0c;可以输出复位信号。 该定时器是一个 12 位的递减计数器&#xff0c;当计数器的值减到 0 的时候&#xff0c;就会产生一个复位信号。如果在计数没减到 0 之前&#xff0c;重置计数器的…

如何使用 NestJS 集成 Passort 和 JWT Token 实现 HTTP 接口的权限管理

&#x1f4a1; 如果你不希望其他人可以随意进出你的房子&#xff0c;那么你需要给你的房子上个锁。 前言 开发一个接口很容易&#xff0c;开发一个具有安全性的接口却不容易。成熟的后端服务项目最注重的一点就是如何保护系统的数据安全&#xff0c;不能让用户无脑的访问操作所…

大数据Doris(四十一):物化视图简单介绍

文章目录 物化视图简单介绍 一、适用场景

利用html2Canvas将表格下载为html

给到我的需求是点击按钮时请求后端接口&#xff0c;根据后端返回的数据&#xff0c;生成表格,并将表格的内容直接下载为html,如下图。 平常做的下载都是后端返回二进制流&#xff0c;这次前端做下载那就必须把页面先画出来&#xff0c;因为下载下来的表格在页面上是不显示的&a…

Keepalived 高可用详解

Keepalived 详解 1、Keepalived介绍 ​ Keepalived是一个基于VRRP协议来实现LVS服务高可用方案&#xff0c;可以利用其来避免单点故障。一个LVS服务会使用2台服务器运行Keepalived&#xff0c;一台为主服务器MASTER&#xff0c;另一台为备份服务器BACKUP&#xff0c;但是对外表…

12月25日作业

串口发送控制命令&#xff0c;实现一些外设LED 风扇 uart4.c #include "uart4.h"void uart4_config() {//1.使能GPIOB\GPIOG\UART4外设时钟RCC->MP_AHB4ENSETR | (0x1 << 1);RCC->MP_AHB4ENSETR | (0x1 << 6);RCC->MP_APB1ENSETR | (0x1 <…

深入剖析LinkedList:揭秘底层原理

文章目录 一、 概述LinkedList1.1 LinkedList简介1.2 LinkedList的优点和缺点 二、 LinkedList数据结构分析2.1 Node节点结构体解析2.2 LinkedList实现了双向链表的原因2.3 LinkedList如何实现了链表的基本操作&#xff08;增删改查&#xff09;2.4 LinkedList的遍历方式 三、 …

静态HTTP的未来:探讨新技术趋势

在Web的世界里&#xff0c;静态HTTP一直是个不可或缺的角色。它就像一个尽职尽责的邮递员&#xff0c;确保数据安全、准确地送达目的地。但随着时代的发展&#xff0c;邮递员也需要跟上潮流&#xff0c;不断学习和进步。那么&#xff0c;静态HTTP的未来会是怎样的呢&#xff1f…

CMMI-项目总体计划模版

目录 1、总体目录结构 2、重点章节概要示例 2.1 第四章 项目管理 2.2 第六章 实施与交付计划 2.3 第七章 运维计划 1、总体目录结构 2、重点章节概要示例 2.1 第四章 项目管理 2.2 第六章 实施与交付计划 2.3 第七章运维计划

从流星雨启程:Python和Pygame下载与安装全过程

文章目录 一、前言二、下载安装过程1.官网下载安装包2.安装python过程第一步第二步第三步第四步第五步安装完成 3.简单测试Python3.1 检查 Python 版本号3.2 打开 Python 解释器3.3 输入你的第一个代码3.4 运行 Python 脚本 4.安装Pygame4.1 cmd命令安装Pygame4.2 pip升级4.3 安…

C++的面向对象学习(6):运算符的重载

文章目录 前言&#xff1a;什么是运算符重载&#xff1f;针对自定义的类与对象类型。一、加号的运算符重载1.引入背景2.所以运算符重载的作用&#xff1a;3.实现对象间的相加代码&#xff1a;号运算符重载①在类中实现加号运算符重载②设计全局函数实现加号运算符重载③改写函数…