- 博客(37)
- 收藏
- 关注
原创 两道经典递推例题
这两个子集相加就是我们的全集,即 dp[i][j]。这样想可能有点难以理解,可以逆着想一下,假设现在你得到了 dp[i - j][j],这其实也就是 i - j 的拆分为 j 份的所有方案的总数,那么把这所有的方案里的那些被划分出来的数整体 + 1,其实也不难发现这就是 dp[i][j] 不算 1 的划分总数了。可以不必纠结于后者为什么是dp[i - x],试想 x 是 3,比它大的假如还剩4,5,6,7, 那么对于4,5,6,7如何排列而言,它们与1,2,3,4是毫无差别的。1 个整数,即不同的分法。
2025-03-21 15:04:10
1014
原创 令人疑惑的滑动窗口两道
给你一个字符串word和一个整数k。返回word的 子字符串 中,每个元音字母('a''e''i''o''u'出现一次,并且包含k个辅音字母的子字符串的总数。0不存在包含所有元音字母的子字符串。1唯一一个包含所有元音字母且不含辅音字母的子字符串是word[0..4],即"aeiou"。3word[0..5]"ieaouq""qieaou""ieaouq"这道题一眼看上去就像一道滑动窗口题,但刷刷刷写完代码提交发现怎么都不对。
2025-03-18 09:00:00
576
原创 Leetcode 1963. 使字符串平衡的最小交换次数
例如平衡字符串 "[[]][]",它的前缀有 "[[]","[[]][" 等,都满足这一性质。因为对于前缀来说,每个右括号的左边,必然有与之匹配的左括号,但左括号不一定有与之匹配的右括号。反之,如果遍历到右括号,且此时 c=0,那么减一后 c 是负数,说明右括号比左括号多,必然存在一个右括号,没有相匹配的左括号,无论后面的字符是什么样的,s 都不可能是平衡字符串。右上,其实我们就可以知道,我在一开始所述的那种方式一定是最优的,因为对于交换两个括号位置而言,没有比这样的交换方式更优的,更能接近答案的方案了。
2025-03-17 14:33:22
325
原创 非典型前缀和两道
我们建立哈希表 mp,以和为键,出现次数为对应的值,记录 s[i] 出现的次数,从左往右边更新 mp 边计算答案,那么以 i 结尾的答案 mp[s[i]−k] 即可在 O(1) 时间内得到。最后的答案即为所有下标结尾的和为 k 的子数组个数之和。则此时子数组 nums[k+1⋯j] 异或的结果一定为 0,此时子数组 nums[k+1⋯j] 一定为美丽子数组,此时只需要找到数组 nums 满足前缀异或的结果为 x 的数目,即可得到以 j 为结尾的美丽子数组的数目。子数组是数组中元素的连续非空序列。
2025-03-06 17:45:49
620
原创 第 26 场 蓝桥月赛
前三道题没什么值得说道的,认真分析就行。不过那个换汤圆的题其实什么操作都不需要做倒是出人意料,我一开始得出这个结论的时候还想着肯定是哪里弄错了。剩下的就是,记得开long long。6.灯笼大乱斗【算法赛】 - 蓝桥云课这道题我想了挺久,后来发现想复杂了。我最初是分类讨论,分为要要交换的和不用交换的,然后不用交换的必胜情况必须要a[i]+b[i]<a[j]+b[j](i<j),然后要交换的必胜情况要b[i]-a[i]>b[j]-a[j](i<j)如此如此,这就似乎变成了一个排序的问题。
2025-02-28 17:32:09
457
原创 Leetcode 647. 回文子串的两种方法
给你一个字符串s,请你统计并返回这个字符串中的数目。是正着读和倒过来读一样的字符串。是字符串中的由连续字符组成的一个序列。s = "abc"3三个回文子串: "a", "b", "c"s = "aaa"66个回文子串: "a", "a", "a", "aa", "aa", "aaa"
2025-02-19 08:30:00
173
原创 Leetcode 72. 编辑距离
当二者不相等时,我们分析,对于题目所述操作而言,增加一个字符与减少一个字符其实是等价的,因为若是初始字符串(即word1)比目标字符串(即word2)少某一个字符,那么对该字符的增加其实就是对目标字符串的对该字符的减少。二者对应的表达式分别为:dp[i - 1][j] + 1 与 dp[i][j - 1] + 1。当word1的第 i 个字符与word2的第 j 个字符相同时,dp[i][j] = dp[i-1][j-1],这很好理解,因为相同的就不需要去修改操作,因此依然沿用上一个即可。
2025-02-18 19:57:54
291
原创 Leetcode 139. 单词拆分
那么 dp[i] 可以用下列方式得到:我们对 dp[i] 之前的 dp[j] 值(i > j)进行搜索,对每一个 dp[j] 值为 true 的位置,我们寻找是否可能有一个单词能满足字符串 s 的前 j 个加上它之后就是字符串 s 的前 i 个,有则可以断定 dp[i] = true,如此递推。返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。
2025-02-12 21:09:40
251
原创 Leetcode 343. 整数拆分
借用容斥原理的思想,试想dp[i](其意义代码注释中已给出)可以用什么表示。我们将 i 拆分为 j 与 i-j 两部分,那么我们可以知道,dp[i] = max({dp[j]*(i-j),(i-j)*j,dp[i]}),这其实就相当于在对每个 i 拆分时去尝试遍历小于它的所有数,即 j ,本质依然是记忆化搜索。顺带提一嘴,这道题可以用贪心,这里给出一个结论:拆分某个数,使其乘积最大的方式是有3拆3,如果最后剩4则保留,否则依然继续拆3(例如如果还剩5的话,拆成3*2是最大的)。你可以获得的最大乘积。
2025-02-05 16:42:22
394
原创 Leetcode 134. 加油站(贪心)
re其实代表着一个分割点,在其之前的所有点都不可能是始发点,因为它们的和值小于0,从它们中任何一个点出发,最后都会需大于供。我们就先贪心,认为i + 1就是我们要找的起始点(至于为什么是i + 1,因为我们需要环行一周,可以把分割点之前的所有加油站简化为一个大加油站,消耗的油量就是其和值。我们无法判断从i+2开始的和值是否能比其和值要大,若是小了,那么我们是无法穿过那个大加油站,完成环行的),以此类推,直到找到最后一个分割点+1(显然若是有解的话一定会有这么一点),也就是i + 1,返回即可。
2025-02-03 14:38:27
582
原创 二分基础两道
典型的二分搜索答案类型题。以最终答案长度作为二分搜索的目标进行搜索。,如果目标值存在返回下标,否则返回。如果不存在符合条件的子数组,返回。个元素有序的(升序)整型数组。是该条件下的长度最小的子数组。找出该数组中满足其总和大于等于。个正整数的数组和一个正整数。
2025-02-03 14:12:16
129
原创 Leetcode 131 分割回文串(纯DFS)
DFS方案1:初始化一个代表分割点的01数组,然后对这个数组的状态使用dfs搜索。这个方案耗时长,空间复杂度也不小。这个方案更快些,具体差别在该方案能及时排除不可能选项,而不是等上一个方案把所有可能情况全列出来然后对每个依次排除。DFS方案2:从前到后直接枚举分割点。分割成一些子串,使每个子串都是。所有可能的分割方案。131. 分割回文串。
2025-01-30 15:18:18
281
原创 洛谷 P10450 [USACO03MAR] Best Cow Fences G
一道经典的二分答案转判断问题,稍微特殊的点就是这道题是实数域上的二分,看上去比较唬人,但实际上比整数集合上的二分好写不少。## 题目分析与思路:给定一个数组A,我们其中要求一个平均数最大的,且长度不小于给定值L的一个子段,那么我们就可以去**用二分枚举这个最大的平均数**,这不难理解。但这道题的难点在于,如何去写check函数,也就是如何去判断我们枚举的这个数。我们对check函数进行如下思考:1.如果我们能在A数组中找到比我们枚举的这个平均数更大的平均数且这个平均数所在的子段大于等于L,那
2024-05-20 18:05:46
468
1
原创 Acwing 95 费解的开关
具体思路是:从00000(也就是0)到11111(也就是十进制的31),我们把0当作不做操作,1当作进行操作,那么从0到31,就应当包括所有的32种操作方案。其中k就是我们遍历0到31的所用的变量,也就是0到31其中一个数,k>>i&1的操作作用是取出k的二进制数从右往左数第i+1个数并判断它是不是1。这道题本质是给我们一个规定为5*5的01矩阵,并给定一个操作可以把某个位置及其相邻位置(即上下左右)的0或1都变为相反的数,即1变成0,0变成1,然后问我们能否在六步内把这个矩阵变为全1矩阵。
2024-05-16 15:17:20
724
原创 P8685 [蓝桥杯 2019 省 A] 外卖店优先级
每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减到 0;而如果外卖店有订单,则优先级不减反加,每有一单优先级加 2。,那么此时,由于我们把有记录和没有记录的时间点都遍历了一遍,自然浪费时间,所以,我们可以只。首先,对于每一家店,我们考虑到需要从时间 1 开始,一直遍历到时间 T,如果有记录,那么。给定 T 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优先缓存中。对于所有评测用例,1≤N,M,T≤105,1≤ts≤T,1≤id≤N。1,对于每一个节点,判断这家店。
2024-04-08 17:13:04
520
1
原创 洛谷 P8656 对局匹配
按照我们上述的思路,假设我们不选i,也就是选i的值b不如a+c大,那么我们最后得到的i-k,i,i+k值分别变成了a,b-a,c-b+a,加起来依然是a+c,代表我们选了i-k和i+k。那我们就接着假设一个值,i+k+k,其值为d,假设b+d>a+c,那么我们就应该选i和i+k+k,而c-b+a与d比较,其实也就是b+d与a+c比较,最后得到的值将他加到上面几个式子中就依然是更大的那个。关于贪心:对于每一个分数i,存在一个i-k与i+k,我们的贪心,就是去判断i与i-k,i+k,到底应该选谁。
2024-04-07 15:49:22
802
原创 洛谷 P8783 [蓝桥杯 2022 省 B] 统计子矩阵
方案从“1,2,12”变成了“1,2,3,12,23,123”,可以自己模拟一下,会发现原来的数列里所有以i(1<=i<x,x为当前增加的数)为开头,以原本的最后一位为结尾的方案都会作为新加入的数的方案之一(也就是上面例子的23和123,都是新方案),再加上这个数本身, 就是r-l+1。看到要求矩阵和我们首先想到二位前缀和,先想出我们的暴力方法:首先预处理得出二位前缀和数组,然后枚举左上角,对每一个左上角都去枚举右下角,根据我们的前缀和方程求得当前这个矩阵的和值是多少,和我们的k值比较即可。
2024-03-29 19:59:04
1352
2
原创 HZOJ 511. 最少操作次数
我这里直接给出答案:a先乘上k,变成123450,然后再加6,也就是123456,继续重复上述操作:1234560,1234567,12345670,12345678,123456780,如此,我们便在六步之内完成操作。先来总结一下我们上述的思路:例如我们现在有1432 和 12,都是k进制数,我们的转变是这样的:14,140,143,1430,1432,其实我们可以总结出:当当前的数字完全等于我们所要的数字的某个前缀的时候,我们将之乘上k是最优方法。当a<=b:ans+=1+b%k,b/=k;
2024-03-24 22:50:04
659
1
原创 洛谷 P1020 [NOIP1999 提高组] 导弹拦截
有这么一个方案:我们维护一个len数组,该数组存储的是某个长度的最长上升子序列末尾项的最小值,简单来说:len[i]存储的就是长度为i的最长上升子序列的末尾的最小值,即在所有长度为i的最长上升子序列中,len[i]存储的就是其中末尾的值最小的那个子序列的末尾值。这不难理解,我们既然要求最长的上升子序列,那么对于同一长度的序列,其末尾的值肯定是越小越好,越小这个序列就可能越长。当然,以上说的是求最长上升子序列,而这道题要我们求的是最长不上升子序列,我们得稍作改变。一行,若干个整数,中间由空格隔开。
2024-03-22 22:34:44
906
1
原创 洛谷 P3478 [POI2008] STA-Station
实际也是很容易想的,本来是以u为根的树,变成以儿子v为根的树,那么v的所有结点的深度都会减1,深度和就会减少size[v],同样地,所有不在v的子树上的结点的深度都会+1,深度和就会加上n - S[v],可以自行画图证明。首先以1为根DFS一遍求出以每个点为根的子树的结S[i]表示以i为根的子树中结点个数。给定一个 n 个点的树,请求出一个结点,使得以这个结点为根时,所有结点的深度之和最大。对于全部的测试点,保证 1≤n≤10^6,1≤u,v≤n,给出的是一棵树。第一行有一个整数,表示树的结点个数 n。
2024-03-21 18:07:41
316
1
原创 洛谷 P1541 [NOIP2010 提高组] 乌龟棋
我的错误思路是:dp[i]的代表到达i格的各项状态,然后这个状态的分数,就等于在此之前的四格中能到达当前格的最大分数加当前格自带的分数。正确的状态选取应该是:dp[a][b][c][d]代表四张卡片1,2,3,4已经分别使用了a,b,c,d张的时候所能获取的最大分数。乌龟棋中 M 张爬行卡片,分成 44 种不同的类型(M 张卡片中不一定包含所有 44 种类型的卡片,见样例),每种类型的卡片上分别标有 1,2,3,41,2,3,4 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。
2024-03-20 16:41:25
1042
1
原创 区间dp:HZOJ #46 切割回文
接着我们模拟一下整个过程:枚举某一个从 i 到 j 的字串的能够切割的位置,然后在这个位置切一刀所代表的最小切割刀数就为这一刀左边的字串的最小切割刀数+这一刀右边的字串的最小切割刀数。最后还有一个需要解释的细节:判断一个字串是不是回文串,我们可以判断:如果dp[i+1][j-1]为零且s[i]=s[j],那么这就是一个回文串,因为这个字串头尾相等且夹在头尾中间的那部分也是回文串。给出一个字符串S,问对字符串S最少切几刀,使得分成的每一部分都是一个回文串(注意:单一字符是回文串)
2024-03-19 15:53:27
373
1
原创 蓝桥双周赛:串门
我们可以思考,若是要遍历整棵树的所有节点并在最后回到原点的话,这棵树的每条路径一定是要走两遍的,也就是总路径之和为两倍树的路径长之和。在纸上画几棵树,然后拿手比划着遍历一下,你就会发现,一定是有一条路径只需要走一遍的,并且这条路径一定以树的顶点为中间的某个点,也就是一定会经过树的顶点,我们将之称之为树的直径。因此我们可以这样:先把所有边权值加起来乘二存起来,然后用dfs,找到树的顶点的最长权值与第二长的权值,然后用前者减去后者就是我们的答案了。关于这道题的图的存储的数据结构,我们选择链式前向星。
2024-03-17 14:31:56
853
1
原创 定长滑动窗口与变长滑动窗口
然后这道题的具体解决思路是这样的:首先两个指针分别指向滑动窗口左右两边,然后右指针不断向右移动,右指针指向的值也不断入队,直到我们最大值与最小值的差大于limit(这个时候我们可以知道,最新一个入队的那个值一定是一个最大值或者是最小值,我们接下来要做的,就是找到与之相对的在他之前进入滑动窗口的最值,将之排除在窗口之外)。最后返回数组中最大值即可。对于每一个长度不超过规定值k的窗口而言,我们将其中的最后一个设为以其为结尾的最长子序和,由于窗口规定了长度,得到的最大子序和一定不会超过k值,也就满足了条件。
2024-03-14 15:43:05
1087
1
原创 HZOJ 284 超市卖货
我们维护一个小顶堆,若其中有i件物品,则该小顶堆代表在i天内要被卖掉的i件货物,其中的每一个元素都代表我们在某一天要卖掉的货。随后我们对每一个货物进行操作,因为我们要求的是最大利润,所以一共有两种情况:若是这件货物的过期日期大于堆中元素,也就是还不需要担心这件货物的过期问题,那么就将其纳入堆中。若是这件货物今天就要过期了,也就是过期日期等于堆中元素,那么我们就把这件货物的利润与小顶堆的头元素利润进行比较,若是这件货物的利润更大,那么我们就将之代替掉小顶堆的头元素,插入堆中。这其中还有贪心的思想。
2024-03-13 15:50:37
395
1
原创 洛谷 P1115 最大子段和
试着选取状态dp[i]为以第i个数为结尾的子段和里的最大字段和,接着去思考状态转移方程。这道题若是按照容斥原理的思想,可以类比最长上升子序列问题——因为二者的状态是一样的——并不适合用容斥原理的思想。一般情况下,咱们肯定会想,以第i个数为结尾的子段和里的最大字段和,应该就是以他前一个数为结尾的最大子段和再加上这个数。也就是说,假设以他前一个数为结尾的最大子段和是一个负数,那么不论这第i个数是正数还是负数,加上另一个负数都会变得比他本身更小,那还不如不加,它自身单独作为一个字段和都会更大。
2024-03-12 21:43:14
398
1
原创 动归经典:三类背包问题
其中没选取第i件物品的最大价值可以被表示为dp[i-1][j],至于选取了第i件物品的,我们可以按以下思路来想:我们先给第i件物品留好一个位置,这样再将所有结果列出即可,也就是:dp[i-1][j-v[i]]+w[i]。给有一个能承重 V 的背包,和n种物品,每种物品的数量有限多,我们用重量、价值和数量的三元组来表示一个物品,第 i 件物品表示为(Vi,Wi,Si),问在背包不超重的情况下,得到物品的最大价值是多少?接下来 n 行,每行三个数 Vi、Wi、Si,分别代表第 i 种物品的重量、价值和数量。
2024-03-06 15:39:15
860
1
原创 洛谷P1106 删数问题
那么,删除哪一个数字能达到局部最优呢?我们要使得删除部分数字后得到的数最小,那么我们可以去想,去按照贪心的思路去想:若是我们只删除一个数字,要使得这个数变得最小,我们应当删除哪一个?怎么浅显易懂的错误,很容易想出反例:8123456789,删除最大的那个变成812345678,但我们若是删除第一个:123456789,这明显比上一个要小。 输入一个高精度的正整数 n(长度不大于 240 位),去掉其中任意 s 个数字后剩下的数字按原左右次序将组成一个新的正整数,现求一种方案,使得新的正整数数值最小。
2024-03-04 21:21:05
522
2
原创 HZOJ #41.墙壁涂色
即我们不难发现,上述代码中,咱们的求解dp[nn][i][j] 只和 dp[nn - 1][i][l] 有关,也就是说,实际上我们dp数组的第一个数不需要1000多,只需要2,完全可以胜任计算。用人话来说就是:前n块墙壁的首尾颜色分别为i与j时的合法方案数=所有前n-1块墙壁的合法方案里去掉其尾块与当前我们要求的这种情况的尾块不相同的情况的其他合法方案累加起来的总数。给一个环形的墙壁涂颜色,颜色一共有 k 种,墙壁被竖直地划分成 n 个部分,相邻的部分颜色不能相同。80% 的数据保证 n≤40,k≤10。
2024-02-29 17:55:17
944
原创 OpenJudge 1088 滑雪
所谓动态规划,就是一个最优化问题,先将问题分解为子问题,并且对于这些分解的子问题自身就是最优的才能在这个基础上得出我们要解决的问题的最优方案,要不然的话就能找到一个更优的解来替代这个解,得出新的最优自问题,这当然是和前提是矛盾的。这道题可以分解成“求每一个点的最长上升子序列”,这就是本题的状态。一般遇到一个动态规划类型的问题,都先要确定最优子结构,还有重叠子问题,这两个是动态规划最大的特征,然后就是要写 动态规划的状态方程,这个步骤十分十分的重要的,写动归方程是需要一定的经验的,这可以通过训练来达到目的。
2024-02-21 18:43:47
1027
2
原创 算法笔记:国王游戏
恰逢H 国国庆,国王邀请n位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前
2023-12-25 16:16:07
1412
3
原创 Leetcode 148.排序链表的三种解法
这里有一个比直接判断“当前传入的头结点是否只有一个这个判断条件”更有效率的方法:直接判断传入的头节点的链表的最大值与最小值是否相等,若是相等,则该链表的所值都应该是相等的,也就没有判断的必要,直接返回头结点即可。接着我们将待排序链表一分为二,分别进行归并排序,得到返回的链表头结点后,由于返回的两个链表都是有序的,我们使用虚拟头结点法,对这两个链表分别同时进行遍历操作,每一次都找出其中的未被找出的最小值然后放入插入带虚拟头结点的链表的末尾。我们首先需要求出链表节点个数的方法,接着进行归并排序。
2023-12-14 14:52:57
90
1
原创 最大占比最长公共子串
这样一个执行次数的数量级为o(n^2)的语句,我们其实可以用一个o(n)的预处理代替,即把当前待排序序列的最小值先提到第一个的位置上来,这样便可以省略这个被执行o(n^2)次的判断语句,从而优化我们的程序运行时间,这也就是无监督的插入排序。但其实我们可以发现,我所加上的那几个判断条件,是位于o(n^2)的遍历中的。乍一看这个方法好像有很多次的遍历操作,出了一个o(n^2)的遍历,后面在查找时还有一个o(mn)的遍历,于是我就想出了第二版的方法,以几个判断条件省略掉了后面的那个o(mn)的遍历。
2023-12-10 17:26:14
113
3
原创 leetcode 03:无重复字符的最长子串的三种解法
我当时的第一反应很简单:用哈希表,一直向后扫描,记录当前的无重复字符长度,然后每当遇到一个重复的字符就将哈希表清空,长度与最大长度比较后归零,然后从当前位置重新开始扫描。维护一个长度等于我们所要求的长度的滑动窗口。我们将不同的可能的最大无重复字符串长度作为二分查找的对象,然后对每一个查找所得的长度做判断:判断整个字符串中是否存在这个长度的无重复字符串,如果是,则让二分法中的head,也就是最小值等于这个值(不等于这个值加一的原因是这个值有可能就是我们要找的最大值),其他部分就和普通二分查找一样。
2023-11-14 21:44:07
232
2
原创 题解思路 001:特殊的密码锁
3.不论是以上的哪一种情况,我们都要使第一个锁变成目标状态,那么在其成为目标状态之后,第二个锁的状态就不能由他自己改变,否则同时也会造成第一个锁的状态改变,反而使我们的进度倒退。由此我们可以得出我们的算法:对第一个锁分两种情况讨论,然后再去遍历之后的锁并改变其状态,如果第一个锁的两种情况都不能得出目标序列,那么就输出impossible。然而让人头疼的是,当你按一个按钮时,跟它相邻的两个按钮状态也会反转。2.分类讨论可知,对第一个锁而言,他要么自己改变状态,要么被他后面的锁改变状态,据此我们分两种情况。
2023-11-02 21:15:42
293
2
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人