dsa加训

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 Listgrid = []m,n = 5,6for _ 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 ansdef all_down(g:List[List[int]])->bool:return sum([sum(g[i]) for i in range(len(grid))])==0def is_valid(x:int,y:int)->bool:return 0<=x<m and 0<=y<ndef 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&1fop >>= 1puz = 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] = 1flip(i,j,puz)if all_down(puz):for row in ops:print(' '.join(list(map(str,row))))return Truereturn Falsefor 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 = 0def check(d:dict,tmp:dict,curr:int):nonlocal ansfor k,v in d.items():if k+curr == targetSum:ans += vif k+curr in tmp:tmp[k+curr] += velse:tmp[k+curr] = vdef dfs(node:TreeNode)->dict:if node is None:return {}nonlocal ansld = dfs(node.left)rd = dfs(node.right)if node.val == targetSum:ans += 1res = {}res[node.val] = 1check(ld,res,node.val)check(rd,res,node.val)return resdfs(root)return ans

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

class Solution:def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:m = defaultdict(int)m[0] = 1def dfs(node:TreeNode,prefix:int)->int:if node is None:return 0cnt = 0prefix += node.valif prefix - targetSum in m:cnt += m[prefix-targetSum]m[prefix] += 1cnt += dfs(node.left,prefix)cnt += dfs(node.right,prefix)m[prefix]-=1return cntreturn 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 = afor nho in lrh:mx = max(mx,base//nho.r)base *= nho.lprint(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.mzph.cn/bicheng/49560.shtml

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

相关文章

巧用 API 接口,尽览京东商品详情

在电商的浩瀚世界里&#xff0c;京东无疑是一座丰富的宝库&#xff0c;而京东商品详情则是其中的璀璨明珠。对于开发者、数据分析师和电商从业者来说&#xff0c;能够巧妙地运用 API 接口获取京东商品详情&#xff0c;无疑是打开了一扇洞察电商奥秘的窗户。 一、京东商品详情的…

【算法与数据结构】并查集

并查集 合并和查询集合的数据结构&#xff0c;经常用于连通图&#xff0c;最小生成树 K r u s k a l Kruskal Kruskal算法&#xff0c;最近公共祖先( L C A LCA LCA​​) 查询的时间复杂度&#xff1a;小于O( l o g 2 n log_{2}n log2​n)近乎O(1) 【模板】并查集 题目描述…

Win10使用VS Code远程连接Ubuntu服务器时遇到SSH公钥错误的解决方案

在使用Windows 10上的Visual Studio Code&#xff08;VS Code&#xff09;远程连接Ubuntu 20.04服务器时&#xff0c;遇到了以下错误&#xff1a; 错误的原因 这个错误消息表明&#xff0c;SSH 客户端检测到远程主机的 ECDSA 公钥已更改。可能是由于以下原因之一&#xff1a…

组蛋白乳酸化 | 调控蛋白Writers、Erasers和Readers

组蛋白修饰的调控可以被归类为三类蛋白&#xff1a;Writers&#xff08;写入者&#xff09;、Erasers&#xff08;擦除者&#xff09;和Readers&#xff08;读取者&#xff09;。Writers是负责在组蛋白上添加修饰基团的蛋白&#xff0c;包括乙酰化、甲基化等修饰。Erasers则是负…

学习记录——day17 数据结构 队列 链式队列

队列介绍 1、队列也是操作受限的线性表:所有操作只能在端点处进行&#xff0c;其删除和插入必须在不同端进行 2、允许插入操作的一端称为队尾&#xff0c;允许删除操作的一端称为队头 3、特点:先进先出(FIFO) 4、分类&#xff1a; 顺序存储的栈称为顺序栈 链式存储的队列&a…

如何使用js 判断在pc打开还是手机

在JavaScript中&#xff0c;你可以通过检查浏览器的userAgent字符串来判断用户是在PC&#xff08;桌面设备&#xff09;上打开页面还是在手机上&#xff08;移动设备&#xff09;打开。不过&#xff0c;需要注意的是&#xff0c;userAgent字符串可以被用户或浏览器插件修改&…

IP数据报结构详解:从基础到进阶

目录 IP数据报的格式 IP数据报首部的固定部分 IP数据报首部的可变部分 实例分析&#xff1a;数据报的分片 生存时间&#xff08;TTL&#xff09;与协议 首部检验和 总结 在网络通信中&#xff0c;IP数据报是至关重要的基本单元。本文将带您深入了解IP数据报的格式及其各个…

【Python】使用抓包Fiddler软件,网络查询 遇到“您的连接不是私密连接”的问题的解决方法

使用Fiddler抓包软件很久&#xff0c;忽然发现网络使用有问题&#xff0c;一点开浏览器就会出现类似下面的页面&#xff1a; 检查了网络情况发现不是网络的问题&#xff0c;也排除了封号的可能。发现只要把抓包软件Fiddler关闭以后就没问题了&#xff0c;就知道问题是出在软件…

国产光电耦合器2024年的机遇与挑战

随着科技的飞速发展&#xff0c;2024年对于国产光电耦合器行业来说&#xff0c;无疑是充满机遇与挑战的一年。本文将深入探讨该行业在技术创新、市场竞争、5G时代、新兴应用领域和国际市场拓展方面的现状及未来前景。 技术创新的黄金期 物联网和人工智能技术的迅猛发展&#x…

Java之集合底层-数据结构

Java集合之数据结构 1 概述 数据结构是计算机科学中研究数据组织、存储和操作的一门学科。它涉及了如何组织和存储数据以及如何设计和实现不同的数据操作算法和技术。常见的据结构有线性数据结构&#xff08;含数组、链表、栈和队列等&#xff09;&#xff0c;非线性数据结构…

医学多模态:多模态知识增强全幻灯病理基础模型

A Multimodal Knowledge-enhanced Whole-slide Pathology Foundation Model 目录 摘要介绍结果2.1 mSTAR概述2.2 病理幻灯片分类用于诊断和治疗mSTAR改善了幻灯片级诊断任务mSTAR改善了分子预测2.3 病理生存分析预测mSTAR 提高了癌症生存预测2.4 多模态能力mSTAR促进多模态融合…

睿考网:中级会计师考试各科分值是多少?

中级会计考试是会计领域的一个重要考核&#xff0c;考试题型包含多种&#xff1a;单选题、多选题、判断题、计算分析题和综合题。这些不同的题型不仅覆盖了广泛的知识点&#xff0c;而且各自的评分标准也是不一样的。为了帮助大家更全面地掌握各类题型的得分规则&#xff0c;睿…

解决:Nacos无法获取远程配置数据,导致项目启动各种配置异常

解决&#xff1a;Nacos无法获取远程配置数据&#xff0c;导致项目启动各种配置异常 一问题描述&#xff1a;1.项目pom依赖版本&#xff1a;2.bootstrap.yml配置信息3.远程配置&#xff1a;默认public命名空间4.启动报异常&#xff0c;显示没有配置数据源&#xff0c;实际远程已…

Mysql随记

对表mysql.user执行DML语句&#xff08;数据操作语言&#xff09;&#xff0c;那么此时磁盘数据较新&#xff0c;需要手动执行flush privileges 语句来覆盖内存中的授权数据。其他的DDL&#xff08;数据操作语言&#xff09;,DQL&#xff08;数据查询语言&#xff09;,DCL(数据…

韦东山嵌入式linux系列-查询方式的按键驱动程序_编写框架

1 LED 驱动回顾 对于 LED&#xff0c; APP 调用 open 函数导致驱动程序的 led_open 函数被调用。在里面&#xff0c;把 GPIO 配置为输出引脚。安装驱动程序后并不意味着会使用对应的硬件&#xff0c;而 APP 要使用对应的硬件&#xff0c;必须先调用 open 函数。所以建议在驱动…

【Pytorch】cumsum的实现逻辑

本文只记录cumsum的实现逻辑的CUDA部分&#xff0c;也即底层调用了CUDA的什么实现算子。 void launch_cumsum_cuda_kernel(const TensorBase& result, const TensorBase& self, int64_t dim) {AT_DISPATCH_ALL_TYPES_AND_COMPLEX_AND2(ScalarType::Half, ScalarType::…

Adobe Character Animator (CH) 安装包软件下载

目录 一、软件简介 二、下载与安装 1. 下载 2. 安装 三、注意事项 1. 硬件要求 2. 兼容性 四、功能介绍 1. 实时面部捕捉 2. 实时语音同步 3. 动作捕捉 五、快捷键操作 CH 提供了一系列快捷键以方便用户快速操作。以下是一些常用的快捷键&#xff1a; 一、软件简介…

django电商用户消费数据分析系统-计算机毕业设计源码20891

摘 要 随着电子商务的快速发展&#xff0c;电商平台积累了大量的用户消费数据。为了更好地理解用户行为、优化商品结构和提升用户体验&#xff0c;本文设计并实现了一个基于Django框架的电商用户消费数据分析系统。 该系统包含后台首页、系统用户&#xff08;管理员&#xf…

Ubuntu Grub引导优化

配置文件 sudo vim /etc/default/grub修改参数 引导菜单等待时间 GRUB_TIMEOUT3自动引导上次选择的系统 如果安装了双系统或多系统&#xff0c;可以考虑配置此参数。 # 此参数默认值为0&#xff0c;引导第一个引导项 GRUB_DEFAULTsaved# 此参数默认没有&#xff0c;需要手…

Hive分布式SQL计算平台

Hive分布式SQL计算平台 一、Hive 概述二、Hive架构三、Hive客户端 1、Hive有哪些客户端可以使用2、Hive第三方客户端 四、Hive使用语法 1、数据库操作2、内部表&#xff0c;外部表3、数据的导入与导出4、分区表5、分桶表6、复杂类型操作7、数据抽样8、Virtual Columns 虚拟列9…