省冲笔记
暴力枚举 前缀和
例1
十次函数 ,已知 ,求
疯狂求导
例2
读入 个数字,有一个数字出现次数大于一半,剩下的数字随机出现,求出现次数最多的数字。(空间限制 的数组)
-
法一
统计每一位上 出现的次数
-
法二
每次抵消掉两个不相等的数,剩下的那个数
例3
题面同例2,大于一半改为大于
- 每次抵消 个数,统计没有被消除掉的数字的历史出现次数
例4
个数字,其中有两个数字是单独出现的,剩下的数字出现次数都为偶数,分别求那两个数字
- 异或之后的结果是两个数的异或值,这两个数必定有一位上互不相同,令 表示二进制表示第 位上是 的所有数的异或值
分割线以下是难题
例1
的灯泡矩阵,每次改变一个位置的状态会影响上下左右的状态,给定初始状态问能不能全灭
- 一个位置上下左右包括他自己最终操作次数和模 的结果是定的 ---> 列 个线性方程(时间复杂度起飞)
- 枚举第一行的开关方法,一路求到最后一行看最后一行能不能全灭 ()
- 设 表示某一位置需要的操作数, 表示某一位置的状态,则 ,从第一行开始将下一行的 表示一下, 一直到最后一行判断是否合法即可
例2
的灯泡矩阵,每次可以选择一列或一行将灯泡反向,给定初始状态,问操作恰好 次最多能让多少列灯泡全为
- 暴力枚举某一列是否亮着以及这一列按了没有,行的状态就确定了,时间复杂度
- 有一性质:对于任意两列而言,当且仅当他们初始状态相同或互补,则他们可以同时变亮,将初始的列分类即可
例3
的矩阵,每个位置都有 个地鼠,有一个 的锤子( 任意),每次可以将这么大的范围内地鼠全部减一(必须保证这一些格子里至少有一个),至少用多少次打完?
- 暴力枚举 ,
思考题
暴力枚举 双指针
例1
给定长度为 的数组,求有多少个区间 满足 。
- 双指针直接枚举,注意 过不了 的情况
例2
张 种卡片,只能买连续的,求最少需要多少钱集齐 种。
- 双指针直接扫
例3
给定长度为 且只含 的字符串,求要获取长度为 且形式为 的字符串最少需要修改多少个字符。
- 统计每个长度为 的串,按除以 的余数分类统计即可
例4
给定长度为 的数组,求有多少个区间异或和等于他们的和。
- 性质:,所以当且仅当区间做与等于 ,满足题意,直接双指针扫
例5
给定长度为 的数组 ,求 的异或和。
- 当 第 位 为 ,当且仅当 ,即 ,对 排序后二分即可。对于 位,对每个数对 取模,剩下的依次操作即可。
例6
- 考虑子任务 : 对于任意一行 ,直接双指针扫;对于任意一行 ,直接输出;
例7(环形序列)
有一个环形序列, 可以指定一个位置将环拆开,接下来和 轮流玩游戏, 先手。 可以任意取走一个元素, 只能从最左边拿,求 能得到的最大分数以及拆的位置。
- 考虑链的情况,将前 个元素记为 ,后 个元素记为 ,满足题意的前缀和一定属于 ,直接将输入前缀和,找出最后大于等于 的位置,将其后作为链的开始,一定满足题意。
- 考虑上述前缀和的情况,如果将前 个移到后面,也就是后面的前缀和要减去前面的前缀和,即是区间修改区间最大值的题,线段树即可
贪心算法
经典模型:偏序关系
例1
给定 个正整数,求其首尾相连能连成的最大整数
- 当成字符串处理,对于结果中任意两个相邻的数字元素,满足 ,即为最优解
例2 P1080 [NOIP2012 提高组] 国王游戏
- 贪心策略:左手右手乘积小的在前。证明:考虑相邻的两个大臣 ,且 前面所有左手的乘积为 ,则采用此策略 ,不采用此策略 ,又因为
经典模型:线段覆盖
例1 P1803 凌乱的yyy / 线段覆盖
- 截止越早,影响越小
例2
给定 个线段,求最多有多少个线段有交集。
经典模型:按位贪心
例1
给定数组 , 组询问给出 ,求 最大值。
- 给 做 01-Trie,贪心即可。
例2
给定一个由 |, ^, &
组成的算式,如 m | 124 ^ 235 & 12423 ^ 12312
,给定 ,求 取何值且 ,式子的结果最大。
思考题
个数字,,设 表示十进制下 进位次数,求 。
- 对任意一个数字,个位有没有数字进位显然可以 处理,十位有没有数字进位可以直接将其看作两位数处理,问题转化为每个数字的每后 位大于等于特定 的有多少个数,排序后对每位二分即可
例1(随机数生成器)
的矩阵中有 中的每个数,左上角走到右下角,经过 个数,排序后将其视作字符串的 码,求给定矩阵后生成的所有字符串的字典序最小的字符串。
- 一定将较小值包含在路径里更优,先求能走到 ,能经过的路径组成的矩阵,再求能走到 ,能经过的路径组成的矩阵,取交集后递归。具体实现可以维护每一行可以经过的区间。
例2
俯视一个蓄水池, 的矩阵中有每个点的高度,水会向四周流,求要使水不溢出边界,最多能蓄多少水。
- 定义某一条路径上最高点为这条路径的长度,则这个点的最大蓄水值为所有这个点逃出边界的路径的最小值,转化为最短路问题,再设一个虚点为边界的集合,问题转化为这个虚点到内部每个点的“最短路” 的和
例3
有 个矮人和 个精灵,每个矮人、精灵都有一个能力值,能力值两两不相同,矮人排成一个 ~ 的环,第 个精灵会从第 个矮人开始挑选第一个无对手的矮人比赛,如何安排精灵出场顺序使胜利场数最多。
- 先考虑链的情况,若任意位置后缀和小于等于下标,则成为了链的情况,问题转化为区间田忌赛马。
- 环形情况证明同 [此题](# 例7(环形序列))
例4
有 个形如 的字符串,将 替换成数字并使 个数单调递增,并使最后的结果数字尽量小,输出方案。
task 1: task 2: task 3:
- Task 1: 枚举 至 的数字
- task 2: 将星号组成数字开始二分
- task 3: 从高位贪心
二分
模板
int now = 0;
for(int stp = len; stp >= 1; stp >>= 1) {
if(now + stp <= len && check(now + stp)) now += stp;
}
// 倍增
例1
四个长度均为 的数组 ,任意 求多少种方案使
- 转化为 ,暴力成两个数组排序双指针即可
例2
件衣服需要晾干,含水量为 ,每分钟蒸发掉 单位水,一个吹风机每分钟可以蒸发 个单位水,求最小时间
- 二分总时间,晾干的不管,没晾干的统计需要吹多少分钟,总时间再和二分的总时间比
例3
个项目组,每个项目组有 个人,每次要从不同的 个项目组里抽一个人,问最多能取多少次
- 二分次数 ,若 ,则可以,
例4
无限长数轴,有一个机器人一开始在 ,有一连串指令形如 ,希望最终停在一个之前没有走过的地方,但是可以放墙,若下一步撞墙则不会走,最少需要几堵墙?方案数?
思考题
有一个动物园,动物都被关在左上角格子,逃出动物园必须从右下角逃出,上下左右均有边界,有两种动物老虎 和牛 ,走过的路径会留下自己的脚印,后面的会覆盖前面的脚印,给定矩阵最后状态,求最少逃出去了几只动物。
例5
字符串,形如 ,最多可以交换相邻两个字符 次,最后最多能得到多少个连续的
- 二分答案。
例6
有一堵墙,堆沙袋最左边位置高度不能超过 ,向右堆和左边一堆相差不能超过 ,要求到最右边得堆个 ,要恰好用完 个沙袋,问最少堆多少列。
- 只和最高点有关,二分。
搜索
例1
见题解
搜索技巧
-
剪枝(估价)
。估价函数必须优于现实。
-
方向
每一步最优+剪枝(?)但是有可能有问题。
可以每一步贪心地限制宽度
-
记忆化
搜索记忆化:记录每个状态的最优解
-
IDA*
限制搜索树深度 ,再加上估价函数。
-
𝛼 - 𝛽 剪枝
两方玩家,一方目的是最大,一方目的是最小,搜索的两步中,假设第一步从大到小搜到了 ,第二步从小
例2
例3 十六数码
- 将左边一列、上面一行 IDA*,剩下八数码。
例4
- 记忆化
- 搜索方向,每次必须打死目前活着的编号最小的鸟
DP
思考题
给定数字 ,分成若干个数字 ,代价为 ,求各个方案代价之和
- 现实意义:班里要分成若干个组,每个组选一个小组长,求方案总数。
- 表示第 个人当不当小组长的方案数,,,甚至还可以矩阵快速幂
状态转移方程
- 考虑 DFS
- 考虑优化(搜索记忆化等)
- 方程?以及初始状态
例题:01 背包
-
dfs(i, v, w)
表示搜过了第 件物品,体积为 ,价值为 -
记忆化优化
-
令 表示第 件用了 的最大价值,那么显然 。接着考虑初始状态。
for(int i = 1; i <= n; ++ i) for(int j = 0; j <= C; ++ j) { dp[i][j] = dp[i - 1][j]; if(j - v[i] >= 0) dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]); }
时间复杂度 ,空间复杂度相同。
-
考虑优化空间,发现每次递推只与上一行有关,利用滚动数组优化。
-
继续考虑优化空间,每一个点只与左下方以及下方有关,若从右边开始,则其正下方的点不需要被用到,直接替换即可
for(int i = 1; i <= n; ++ i) for(int j = C; j >= v[i]; -- j) dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
最优子结构
在上个例子中,最优子结构意思就是在 确定时,只有在此时的 最大时,最终结果是最优解。
极小状态集
即用最少的参数表示状态,不唯一
优化
- 去除冗余结构,找到极小状态集
- 换最小状态集
- 去掉看似有用的状态
DAG
技巧
二进制拆分(单调队列)
每个数字选或不选的两种状态,则拆成 个数字最多能表示的数量为 ,需要注意当总量不为 时,拆分总和不能超过物品总和
例1 01背包,但是
- 对于每一个 ,可以枚举可能的所有 和 ,所有 更大, 更小的状态都可以舍弃。
例2 最长上升子序列
- 令 表示前 个的最长长度,则 ,时间复杂度
- 考虑降维,可以看到上面的公式有两个约束条件,但是可以通过分治的思想将 的条件消除。设
solve(1, n)
表示处理区间 的函数,则表示为 - 令 表示前 个数选了长度为 的 LIS 最后一个数,则能更新 的条件是 ,实际上也只用了 一维。
例3 最长公共子序列
-
设 表示 数组前 个, 数组第 个的 LCS 长度,则显然
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); if(a[i] == b[j]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1]);
-
当 ?设 表示第一个串前 个 LCS 长度为 时第二个串的最早结束位置 ,则
dp[i][len] = min(dp[i - j][len], B.find(dp[i - 1][len - 1] + 1,A[i]));//j <= iB.find(n, m) 表示在 B 里从 n 开始第一个与 m 值相同的位置
例4
有 盘菜,每盘菜有两个属性价格 和美味程度 ,两个人轮流选菜吃,A 每次选价格最贵,价格相同味道最好;B 的目标是使自己吃到的 最大。B 每次选取最优决策,求 最大值。
- 前 个位置 B 只能吃到 个,先按照 A 的策略排序
例5
网格型地图,从左上角出发,要到右下角,每个格子里有一只怪物,攻击力为 ,血量为 ,初始有一个攻击力 ,有 次技能可以释放,技能放完之后可以将之后路径上 格中打死的怪物的攻击力在技能时限内加到自己身上,用完技能后有 秒 CD,攻击时回合制,每回合用一秒,只能向右或向下。
- 表示坐标为 用了 次技能 CD 剩下 秒,发现用技能最多只会影响后续 的矩阵的攻击力,当不使用技能时可以 转移,使用技能 DFS 转移即可。
例6
计数题。
- 先考虑 DFS,
dfs(i, j, k)
表示 A 串选到第 个,B 串选到第 个,一共选了 个串。 - 设计 dp 状态, 表示 A 串选到第 个,B 串选到第 个,一共选了 个串的方案数,
例7
有数轴上 个房子,每个房子住的人为 ,可以选 个安全屋,避难时总是去最近的安全屋,问所有人避难时的总的路程最小。(路程定义为距离的平方)
- 表示上一个在 ,这一个在 ,一共选了 个的最小总距离。于是 可以转移到 ,复杂度
- 考虑结果,本质上是分成了 个区间,求每个区间放在哪里。 表示选到第 个位置时选了 个,则 , 可以预处理。
例8
但是砖块必须完全暴露在外才能打,。
- 每个砖块依赖于下面的一个菱形,将其逆时针旋转 变为一个直角坐标系,发现第 列的下面 个只依赖于第 列的前 个, 表示第 列选了 个目前一共选了 个的最大值,则
例9 最长公共上升子序列(LCIS)
。
- 设 表示第一个串前 个 LCIS 长度为 时第二个串的最早结束位置 ,则 , 表示在 B 串中从位置 寻找 的第一个位置,最小值可以数据结构维护一下,因为有两个限制条件 和 。
例10
个城市, 条有向边(有距离),每个城市有一个加油站费用为 ,每次加油可以加到 。有两种走法:
- 如果目前油量大于 ,可以选一条有向边走,油量减 。
- 加油。
组询问,问从 出发,带了 块钱,要至少开 的距离,求剩下最多多少钱,无解输出 。
- 要处理 表示从 出发有 元钱最远能开多少距离,显然单调,可以二分。, 表示从 出发到 最多走 步的最长距离。考虑拓展 意义,令 表示从 出发到 ,最多走 步的最长距离,则 。倍增优化第 维(例:)
思考题
一棵多叉树的先序遍历,规定儿子编号从小到大,给定先序遍历,求有多少棵不同对应的树。
- 表示区间 是一棵子树的方案数, 表示将区间 分割成若干个单调递增的序列的方案数,则 ,则 。
例11
一次性抽 个棋子排成一行,每一种棋子用一个字母表示,两种策略:
- 删掉一颗棋子
- 三个相邻的同级同种棋子,合成一个高一级的棋子
给定每种棋子每一种棋子的价钱,问最后剩下棋子的最大价值。
- 从结果看,是连续的若干种棋子连在一起, 转移到 ,条件为 ,价值加上 到 的同种颜色的最大值。
区间 dp
四边形不等式优化
以石子合并为例,记 为区间 内取最优解的分割位置,则 ,分割区间 时从 到
例1(?)
共有 个人,老师、学生对半分,站成一排,给 对配对关系 ,一个老师和一个学生配对,每次只能相邻的两个人去上课,求有多少种方案使全部人出去。
- 表示区间 的方案数,则转移要么是两边个扩大一个( 能配对),要么是分割点两边乘积再乘上 ,但是会重复。
例2
个人悲惨值为 ,有一个栈,第 个人上场卖惨值是 ,调整入栈出栈顺序使卖惨值之和最小
- 上一个人其他人的悲惨值都加上自身的悲惨值。则
例3
个怪物,每个怪物攻击力是 ,杀死一只怪物代价为左右怪物攻击力加上他本身的攻击力,最两边不能杀,求杀死所有的怪物总代价最小。
- 表示区间 只剩头尾最小总代价,枚举最后一个被打死的怪物,则
例4(?)
盏灯,每盏坐标 ,每个路灯下都有小朋友,有人过来时数 秒之后它会把灯关掉,忽略开灯时间,走一个单位需要 s,问最少需要多长时间全点亮以及开灯的最小字典序。
例5
个点的二叉树的中序遍历每个点权值为 ,最小化 ,
- 同例2
例6
张牌有分别的坐标,移动牌时必须放在这张牌加一的位置上,移动代价为两个位置之间距离,最小化代价。
- 按数字大小带坐标
sort
,直接区间dp
例7
长度为 的正整数序列 ,长度为 的正整数序列 ,每次可以从 中删除一段连续的等差数列(两个数也算),公差必须在 中,最多能删多少个?
- 题意换成只能删长度为 或 的等差数列
- 表示前 个最多能删多少个,则
思考题
例8
个人参加考试,每条信息格式如下: 表示有 个人严格比自己高, 个人严格比自己低,求最多有几个人说了真话。
- 表示前 个人最多有多少个人说真话,则 , 表示有最多多少个人说自己的排名在区间 内。
状压 dp
例1
的网格用 或 的砖块密铺,多少种铺法?
-
考虑一行一行 DFS,参数为
dfs(i,sta)
,其中 状压表示第 行的状态 -
计数 dp 模型
-
再考虑 DFS,
dfs(j, nxt, i, sta)
表示目前考虑第 行的第 列,下一行的状态为 ,当前行的状态为 -
从左上角开始从左到右从上到下考虑,当枚举到某一个格子的时候,只有左边下面一行和右边的状态不确定,令 表示改填 ,当前轮廓线上的状态是 的方案数。初始状态:,最终状态 。转移:
- 第 列本来就是 ,不能铺,要把状态的这一位改成
- 当前是 ,竖着铺:状态的这一位变成 。横着铺:这一位和下一位都变成 ,但条件是下一位是
例2 炮兵阵地
例3
“L”型砖块(田挖掉一个)铺满 的网格,多少种铺法?
- 倍增思想, 表示从上一行的状态是 时开始走恰好 行走到目前处理的这一块的最后一行状态是 的方案数。那么可以得出
例4
~ 之间满足如果选了 , 都不能选,最多能选多少个数字
例5 TSP 问题
个点 条边的图,起点开始走最终回到起点,每个点至少经过一次,求最短路。
- 表示目前状态为 ,目前在 的最短路,顺推转移
例6
- 表示当前钥匙状态,走到了第 个关键点(起点终点钥匙门)的最小总代价,则只关心从某个关键点到另一个关键点中间经过哪些关键点,那我们不妨预处理从某个关键点到其他关键点中间所不经过任何关键点的最短路径 ,则现在显然是一个有环的 dp,不妨将每个状态当作点,跑最短路。
- 第二维只有钥匙。暴力每一个
例7
klb 拿了 个长度为 的字符串 ,,,,构造一个最短串使这 个串都是构造出来的字符串的字串
- 同 例5
例8 P3959 [NOIP2017 提高组] 宝藏
例9
从 ~ 之间分给三个集合,使得分给 的和分给 的集合中可以做到两两互质,求方案数。
- 把所有数字按照最大质因子和 的大小关系分类,小于的直接
例10
~ 选若干个数字,使 , 组询问给出 ,若 必选,求方案数。
- 题意转化为 使
例11
盏灯, 个开关,告诉每个开关对应的多盏灯,显然开关按与不按的状态一共有 种状态,定义一种状态价值 是亮灯个数的三次方,求
例12
无向图 , 个点, 条边,最小要选多少的边权和使图联通且删除任意一条边图仍联通
- 表示某状态构成环的最小总代价, 表示以 为起点, 为终点的某状态构成链的最小总代价,dp 即可
博弈
平等组合游戏
两人游戏,轮流操作,(通常有限的)状态集,有终止状态,可以在有限的状态内结束,规定好合法的状态转移,规则对于双方相同
例1
个石子,每轮最多取 个,最少取一个,取完的胜,问先手还是后手胜?
- 从小往大处理出来剩 个时能转移到的状态以及状态的必胜/必败
例2
同 例1,每次最多取现在剩下的的石子除以 向上取整个
- 结论: 先手必败
例3
堆石子,每堆 个,每次可以在某一堆里取若干个,谁把所有的取完谁赢,先手 / 后手胜?
-
结论:异或和为 先手必败
-
证明:定义 表示 ,说人话就是到不了的最小数字的 值。 表示集合 中从 开始第一个没有出现过的数字。考虑单堆,则剩下 个时 。考虑例 1 的情况,则 值如下:
sta 0 1 2 3 4 5 6 7 8 … sg 0 1 2 3 0 1 2 3 0 … sg 定理:多个游戏同步进行,谁不能操作谁输,那么先手必败当且仅当 sg 值的异或和为 。
证明:
必要性:当一个状态的 sg 值异或和等于 ,能到达的所有状态 sg 值异或和不等于 。
改了某一个值 sg 值一定改变,异或和自然不等于 。
充分性:如果当前 sg 值异或和不等于 ,则至少存在一种决策,使得局面的 sg 值异或和等于 。
令 ,对于每一位是 的考虑,挑某些 值将这一位上的 改为 。
例4
堆石子,每堆 个,每次可以在某一堆里取若干个,谁把最后一个取走谁输,先手 / 后手胜?
-
先手必胜:局面的 sg 值异或和不为 ,且至少存在一个子局面的 sg 值大于 ,或局面的 sg 值异或和为 ,不存在子局面的 sg 值大于 。
-
先手必败:局面 sg 值异或和不为 ,且全部子局面的 sg 值 小于等于 ,或局面的 sg 异或和等于 ,至少存在一个子局面 sg 值大于1
-
通法:讨论 sg 值异或和等不等于 以及讨论存不存在子局面 sg 值 大于 ,相互转化的方法
例5
给你 堆石头,两种操作:从其中一堆拿走一颗或合并两堆,不能操作算输。
- 大于 4 的偶数-->4,大于 3 的奇数-->3,dp即可
例6
层楼梯,每层楼梯上有 个石子,每次可以从某一层上拿一部分到下一层去,拿到第 层就不能操作了,不能操作的输。
- 所有奇数层异或和等不等于 。
例7
一串项链 个宝石,每次可以连续取走 个宝石,取走最后一个的赢
- 当 ,先手拆成一条链,后手把中间的拆掉使之对称,之后后手对称操作即可
- 当 ,讨论 的奇偶
例8
堆糖,每堆有 个,每轮选择当前最多的一堆吃光或者每堆吃掉一个,吃掉最后一个的输。
边界全是先手必胜。右、上方的点有一个先手必败,那就是先手必胜;否则是先手必胜。如果一个点右上方不是边界,那么这个点胜负和他右上方胜负一样。如果这个点是边界外一圈的点,那么他右边或者上边的点是胜负交替的。考虑原点向右上的到达的边界外一圈的点。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探