dsa加训

news2024/9/22 1:30:53

refs: OI Wiki - OI Wiki (oi-wiki.org)

1. 枚举

POJ 2811 熄灯问题

refs : OpenJudge - 2811:熄灯问题

如果要枚举每个灯开或者不开的情况,总计2^30种情况,显然T。

不过我们可以发现:若第i行的某个灯亮了,那么有且仅有第i行和第i+1行的同一列的灯可以影响到它(把它关掉)。

如果某一行的操作已经结束,那么就只有下一行能影响到它了。因此我们可以仅仅枚举第一行的所有操作序列。接下来的每行都会尝试去“填补”上一行产生的问题(也即上一行的没有熄灭的灯)。

在枚举第一行的操作序列时,我们可以发现这是一个长度为6的0-1串,因此转换为十进制后,范围在0-63,我们可以用一个range(64)的列表以及位运算来实现这个操作。

from typing import List

grid = []

m,n = 5,6

for _ in range(m):
    grid.append(list(map(int,input().split())))

# 仅枚举第一行,检查剩余行 操作从全0到全1
f_ops = [x for x in range(64)]

directions = [
    (0,0),(-1,0),(0,1),(1,0),(0,-1)
]

def mat_clone(g:List[List[int]])->List[List[int]]:
    r,c = len(g),len(g[0])
    ans = [[0 for _ in range(c)] for _ in range(r)]
    for i in range(r):
        for j in range(c):
            ans[i][j] = g[i][j]
    return ans

def all_down(g:List[List[int]])->bool:
    return sum([sum(g[i]) for i in range(len(grid))])==0

def is_valid(x:int,y:int)->bool:
    return 0<=x<m and 0<=y<n

def flip(x:int,y:int,puz:List[List[int]]):
    for direction in directions:
        nx,ny = x+direction[0],y+direction[1]
        if is_valid(nx,ny):
            puz[nx][ny] = 1-puz[nx][ny]

def check(fop:int)->bool:
    ops = [[0 for _ in range(n)] for _ in range(m)]
    for i in range(n-1,-1,-1):
        ops[0][i] = fop&1
        fop >>= 1
    puz = mat_clone(grid)
    for i,op in enumerate(ops[0]):
        if op==1:
            flip(0,i,puz)
    
    for i in range(1,m):
        for j in range(n):
            if puz[i-1][j]==1:
                ops[i][j] = 1
                flip(i,j,puz)
    if all_down(puz):
        for row in ops:
            print(' '.join(list(map(str,row))))
        return True
    return False

for f_op in f_ops:
    if check(f_op):
        break

我觉得这道题我写的已经比较优雅了,仅仅60行。

假设行数为m,列数为n,则时间复杂度O(mn*2^n)

3. 递归

LC 437 路径总和Ⅲ

refs: 437. 路径总和 III - 力扣(LeetCode)

向下深搜,维护任意一个子链的路径和到哈希表里,key是路径和,v是出现次数。每次把当前节点加到其下的子链的路径和上去,如果发现为targetSum,则根据v更新答案。

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:
        ans = 0

        def check(d:dict,tmp:dict,curr:int):
            nonlocal ans
            for k,v in d.items():
                if k+curr == targetSum:
                    ans += v
                if k+curr in tmp:
                    tmp[k+curr] += v
                else:
                    tmp[k+curr] = v

        def dfs(node:TreeNode)->dict:
            if node is None:
                return {}
            
            nonlocal ans
            ld = dfs(node.left)
            rd = dfs(node.right)

            if node.val == targetSum:
                ans += 1
            res = {}
            res[node.val] = 1
            check(ld,res,node.val)
            check(rd,res,node.val)
            return res
        
        dfs(root)
        return ans

还有种写法更加简洁,运行时间也更短的:维护任一子链前缀和并置入哈希表,key是前缀和,v是出现次数。查询去掉多少个前缀和可以将当前节点和剩余前缀和加起来等于targetSum即可。

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:
        m = defaultdict(int)
        m[0] = 1
        

        def dfs(node:TreeNode,prefix:int)->int:
            if node is None:
                return 0
            cnt = 0

            prefix += node.val
            if prefix - targetSum in m:
                cnt += m[prefix-targetSum]
            m[prefix] += 1

            cnt += dfs(node.left,prefix)
            cnt += dfs(node.right,prefix)

            m[prefix]-=1

            return cnt

        return dfs(root,0)

注意维护哈希表时记得回溯时去掉当前prefix,不然可能导致a链上的前缀和被b链上的节点所用。也即

m[prefix] -= 1

时间复杂度:瓶颈哈希表,O(n)

5. 贪心

NOIP2012提高组D1T2

refs: 国王游戏 - Vijos

这题挺难的,思维上想不到,不是dsa知识储备的问题。

设第i个大臣手上的数为

(a_i,b_i)

对于任意合法的(i,i+1),设第i个大臣前的左手数字的乘积为s。金币最大数有以下两种情况:

  1. (i,i+1):

max(\frac{s}{b_i},\frac{s\cdot a_{i}}{b_{i+1}})

  1. (i+1,i):

max(\frac{s}{b_{i+1}},\frac{s\cdot a_{i+1}}{b_i})

若前者站位方式更优于后者,则:

max(\frac{s}{b_i},\frac{s\cdot a_{i}}{b_{i+1}}) < max(\frac{s}{b_{i+1}},\frac{s\cdot a_{i+1}}{b_i})

等价于(通分+约分):

max(b_{i+1},ai\cdot bi) < max(b_{i},a_{i+1}\cdot b_{i+1})

也就是说,对于任意相邻的两个大臣,计算上式,如果前者更大,那么这两个大臣应该互换位置。

注意,这个过程是递归的,如果(i,i+1)换了位置,那么还得检查(i-1,i+1)要不要换位置……直到不需要换位置为止。核心思想是每次交换都把相邻两人之间的最大金币数削减到更小的值

那么这个一直交换的过程相当于什么呢?显然,是冒泡排序

所以在具体实现时,我们可以把每个大臣手里的数封装为一个类实例,然后覆写比较类实例的函数,直接对实例列表排序即可(冒泡排序本身是排序的一种实现方式,既然我们要对整个列表排序,为什么不用更快的排序方式呢?比如py提供的内置快排)

n = int(input())

a,b = tuple(map(int,input().split()))

from functools import total_ordering

@total_ordering
class nh:
    def __init__(self,tup:tuple) -> None:
        self.l = tup[0]
        self.r = tup[1]

    def  __lt__(self,x)->bool:
        if isinstance(x,nh):
            return max(x.r,self.l*self.r) < max(self.r,x.l*x.r)

lrh = [] 
for _ in range(n):
    lrh.append(
        nh(tuple(map(int,input().split())))
    )

lrh = sorted(lrh)

mx = 0
base = a

for nho in lrh:
   mx = max(mx,base//nho.r)
   base *= nho.l

print(mx) 

时间复杂度O(nlogn),瓶颈在排序。

不过这里还有一个问题,我们不妨从归并排序的角度来考虑。

假设我们现在有两个分开的子序列,不妨叫L和R好了,那么在归并时,我们不断从L和R的头部元素中选个最小的放进去。例如,一个归并的结果可能是:

[\;L[0]\;R[0]\;R[1]\;]

也就是说:

L[0]<R[0]<R[1]

这个不等式拆成两份看都没什么问题,毕竟子序列有序,但问题是,为什么

\begin{cases} L[0]<R[0]\\R[0]<R[1] \end{cases}

能推出来

L[0]<R[1]

从直观感受上来说,当比较类实例时,我们比较的是相邻元素在上式中的值,当两个元素不相邻,为什么会有传递律

这个还需要从数学上给出一个数值的证明。我们假设有三个大臣,其手上的数为:

\begin{cases} (l1,r1)\\ (l2,r2)\\ (l3,r3) \end{cases}

根据上述定义,有:

\begin{cases} max(r_2,l_1\cdot r_1) < max(r_1,l_2\cdot r_2)\\ max(r_3,l_2\cdot r_2) < max(r_1,l_3\cdot r_3) \end{cases}

我们知道,若:

\begin{cases} a < b \\ c < d \end{cases}

max(a,c) < max(b,d)

于是有:

max(r_2,r_3,l_1\cdot r_1,l_2\cdot r_2) < max(r_1,r_2,l_2\cdot r_2,l_3 \cdot r_3)

去掉重复项:

max(r_3,l_1\cdot r_1) < max(r_1, l_3 \cdot r_3)

也即(l1,r1)<(l3,r3)的定义。

因此传递律得证,我们可以放心大胆地排序了。

有感

从大二上第一次接触到贪心算法开始,我就觉得这是一个很容易盛产“江湖骗子”的知识点。它不像dp,人家是有严格的状态定义和转移方程的,所以比较令人放心。但是贪心更偏思维和直观感受,或者说就是口胡。说难听点,我觉得除了个别显然且直观的贪心算法的证明(如最短路反证法),其他证明,就算是写在了教科书上,也是“以其昏昏,使人昭昭”,很多时候看到一个证明,我的感受就是:“啊?这就证出来了?”包括我自己写的有关贪心算法的证明,十个里面估计有九个都是在胡扯。这个东西对于我来说几乎无法证明,甚至无法理解别人的证明。

拿这个国王游戏举例,覆写lt然后直接对实例列表进行排序,可以A,而且跑的还很快。可关键在于,如果按照最朴素的邻项交换,那么就会是一个O(n^2)的冒泡排序,虽然跑得慢,但是人家实打实地比较了任意两个元素之间的大小。但如果是归并或者快排,无疑建立在了这个类的实例遵循传递律的基础上,那么传递律又是谁保证的呢?因此我觉得讨论传递律是非常必要的。我在题解区看了一圈,有不少跟我一样直接对实例列表调内置库的sorted的题解,但没人说过传递律的问题。可以想见一些贪心算法的证明中到底遗漏掉了多少细节和重要的地方。

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

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

相关文章

MQ传递用户信息

theme: nico 你们好&#xff0c;我是金金金。 场景 购物车里面有5个商品&#xff0c;用户勾选了并且提交订单了&#xff0c;此时需要删除购物车对应勾选的商品&#xff0c;mq的话涉及到传递用户信息~因为删除对应的购物车商品是需要传递用户信息来知晓对应用户的 生产者 消费者…

SolidWorks 二次开发--创建属性页面及控件事件(二)

在前文中我们学习了如何创建和显示属性页面&#xff0c;本章节将重点介绍如何向属性页面中添加控件。控件是属性页面的基本组成部分&#xff0c;可以是文本框、按钮、复选框等&#xff0c;用于用户交互和数据展示。接下来我们将看到如何定义、配置和操作这些控件&#xff0c;让…

ROS2入门到精通—— 2-8 ROS2实战:机器人安全通过狭窄区域的方案

0 前言 室内机器人需要具备适应性和灵活性&#xff0c;以便在狭窄的空间中进行安全、高效的导航。本文提供一些让机器人在狭窄区域安全通过的思路&#xff0c;希望帮助读者根据实际开发适当调整和扩展 1 Voronoi图 Voronoi图&#xff1a;根据给定的一组“种子点”&#xff0…

【保姆级介绍PyCharm安装教程】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 🤹目录 🤹前言🤹前提条件🤹安装步骤🤹前言 🥰PyChar…

外卖霸王餐系统架构怎么选?

在当今日益繁荣的外卖市场中&#xff0c;外卖霸王餐作为一种独特的营销策略&#xff0c;受到了众多商家的青睐。然而&#xff0c;要想成功实施外卖霸王餐活动&#xff0c;一个安全、稳定且高效的架构选择至关重要。本文将深入探讨外卖霸王餐架构的选择&#xff0c;以期为商家提…

仕考网:公务员考试申论答题技巧

在国家公务员考试的申论部分&#xff0c;要想取得好的成绩&#xff0c;关键在于掌握有效的写作方法。 1.文章结构 申论考试中&#xff0c;一个清晰、逻辑性强的结构是至关重要的。这种结构能迅速找到核心论点和支持论据。 2.紧贴主题 申论试题经常设置特定条件或要求&#…

谁说软考高级难?这个“通关秘籍”人人都能掌握

今天给大家分享一个非常有效的学习方法&#xff0c;来自网友的经验精华&#xff0c;仅供参考。 尝试了这个方法之后&#xff0c;你会觉得软考高级考试真的有点容易了&#xff01;想要及格拿证都是分分钟的事情&#xff01;按照我的方法&#xff0c;就算你从来没有考过初级和中级…

Python+Flask+Mysql or sqlite,搭建个人博客

昨天逛csdn看到了一个前端小框架界面&#xff0c;想着试着搭建一下要了一份源代码&#xff0c;因为我自己本身好久没有接触&#xff0c;好多知识有忘记了&#xff0c;只能重温python爬虫问题了&#xff0c;随后跟博主要了一份源码&#xff0c;作为练习使用&#xff0c;也不是很…

Java根据code获取枚举优化

Java枚举获取优化 需求原始解决方案优化方案1. 首先创建base接口。2. 创建枚举工具类3. 需要使用工具类的枚举&#xff0c;实现BaseEnum接口即可4. 测试使用 拓展 需求 自己模拟两个枚举&#xff0c;假设业务中需要用到 Example1StatusEnum.java package com.zdh.zdhenum;/*…

【大师与bug里特】M_Studio《王国之梦》学习笔记

1️⃣ Object & object(✅) 之辨 《7.泛型事件框架〈余2min左右时〉》 不然inspector窗口的最后一行&#xff08;告诉我们订阅者是SceneLoadManager它身上挂了☝️ObjectEventListener用来监听这个事件 有多少个事件注册到这里来了都能够看到&#xff09;还是不会出现 加上…

光谱分析仪进行一些常规参数测量的方法有哪些?

光谱分析仪在光纤通信产品中的应用&#xff0c;以AQ6370光谱分析仪为例&#xff0c;详细说明了使用光谱分析仪进行一些常规参数测量的方法。这些参数包括光谱的带宽、边模抑制比、增益、噪声系数和系统OSNR等。文章中还提到了光谱分析仪的一些基本功能&#xff0c;如屏幕显示测…

人大金仓亮相国际金融展,助力数字金融跑出“加速度”

7月19日至21日&#xff0c;由商务部批准、中国金融电子化集团有限公司主办的2024中国国际金融展&#xff08;以下简称“金融展”&#xff09;在北京国家会议中心举办。作为数据库领域国家队&#xff0c;人大金仓携金融领域创新成果与解决方案亮相本次金融展&#xff0c;获得了业…

ChatTTS真人文本转语音模型,富有韵律与情感,且免费开源

上期图文教程&#xff0c;我们分享了微软TTS真人转语音大模型&#xff0c;但是微软的TTS模型只有针对新用户免费一年&#xff0c;其他用户都是收费的&#xff0c;虽然微软开源了部分TTS的功能&#xff0c;但是针对真人类似的富有情感的TTS模型并没有进行开源&#xff0c;本期介…

代码随想录day21 二叉树最后一天 || 669修剪二叉树 108将有序数组转变为平衡搜索二叉树 538把搜索二叉树变为累加二叉树

669修剪二叉树 力扣题目链接 题目描述&#xff1a; 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果…

Anything LLM ,构建自己的 RAG 架构 LLM,学习自己的知识库

本心、输入输出、结果 文章目录 Anything LLM ,构建自己的 RAG 架构 LLM,学习自己的知识库前言什么是Anything LLM?主要功能与技术原理功能亮点技术原理安装与使用方法初始设置模型部署案例应用企业知识管理个性化教育助手内容创作助手Anything LLM 开源新Anything LLM ,构…

DolphinDB Web 端权限管理:可视化操作指南

在现代数据库管理中&#xff0c;高效和直观的权限管理对于用户的数据安全是至关重要的。过去 DolphinDB 用户需要依赖系统脚本来管理用户和权限&#xff0c;这对于缺乏技术背景的管理员来说既复杂又容易出错。 为了提升用户体验和操作效率&#xff0c;DolphinDB 目前在 Web 上…

解决nvm use无效问题

首先安装先确定没错。nvm安装教程 问题&#xff1a;nvm use 后 node和npm均无法使用&#xff0c;nvm list也没有*号 原因&#xff1a;nvm目录下没有nodejs文件夹 解决办法&#xff1a;先nvm install 一个版本&#xff0c;复制&#xff0c;改名nodejs&#xff0c;比如我这里是复…

unity2D游戏开发02添加组件移动玩家

添加组件 给PlayGame和EnemyObject添加组件BoxCollider 2D碰撞器&#xff0c;不用修改参数 给PlayGame添加组件Rigibody 2D 设置数据 添加EnemyObject&#xff0c;属性如下 Edit->project setting->Physics 2D 将 y的值改为0 给playerObject添加标签 新建层 将PlayerObj…

MacOS安装SDKMan管理Java版本

文章目录 1 简介2 安装与卸载2.1 安装2.2 卸载 3 使用3.1 查看其他工具&#xff1a;支持 Ant, Maven 等3.2 查看Java版本3.3 安装Java&#xff0c;加上相关的版本3.4 设置Java版本(全局)3.5 只在当前窗口生效3.6 卸载1 默认环境无法卸载 4 jdk安装的位置5 与IDEA集成参考 1 简介…

【目标检测实验系列】EMA高效注意力机制,融合多尺度特征,助力YOLOv5检测模型涨点(文内附源码)

1. 文章主要内容 本篇博客主要涉及多尺度高效注意力机制&#xff0c;融合到YOLOv5s模型中&#xff0c;增加模型提取多尺度特征的能力&#xff0c;助力模型涨点。&#xff08;通读本篇博客需要7分钟左右的时间&#xff09;。 2. 简要概括 论文地址&#xff1a;EMA论文地址 如下…