06 2019 档案
摘要:众所周知,乘法逆元可以通过Exgcd和费马小定理求解,如果我们在题目中需要预处理连续的一段数的逆元,我们需要更高效的算法求解。 1.线性递推求解乘法逆元 首先,我们声明在下列计算中同余均是在模p意义下 我们可以简单计算1-1≡1 考虑任意正整数i,假定i-1的逆元已经正确计算,我们递推方程的计算过程
阅读全文
摘要:众所周知,扩展欧几里得算法(下文统称Exgcd)能求解二元一次方程的整数解,乘法逆元、线性模方程等。本文我将简单的介绍该算法。 形如ax+by=gcd(a,b) 的方程,我们可以用Exgcd求出其最小整数解。我们考虑如何求解。 当b=0时,方程右边的值为a,那么显然可得x=1,y=0。 现在假设当前
阅读全文
摘要:欧拉函数是指对于正整数x,小于或等于x的数中与x互质的数的数量,通常用φ(x)表示。 我们先看一道例题 对题意进行分析,可以得到最小生成树中的两个直接连通的点的gcd一定是1,我们要统计最小生成树的个数,也就是求1~n每个数的欧拉函数值之和。 因此,对于一个正整数x,我们需要计算欧拉函数φ(x)。
阅读全文
摘要:这道题实质上是求序列的最长不下降子序列 按照题意,我们要求出最小的代价,也就是说我们要让尽可能大的代价不动,也就是求出最长不下降子序列,之后用序列的和减去它即可。
阅读全文
摘要:一道不怎么简单的dp题 我们定义状态f[i][j][k][val](其中val∈{0,1})表示A串的前i个字符,分成k段,与B串的前j个字符匹配,并且A[i]选/不选的方案数。 那么我们考虑状态的转移, 当a[i]==b[j]时,f[i][j][k][1]可以从f[i-1][j-1][k-1][0
阅读全文
摘要:最短路的扩展题。 在没堵车之前,他会按照这张图的最短路走,所以我们跑一下dijkstra求一遍不堵车情况下的最短路,同时记录最短路径上每一个点的前驱。 考虑堵车的情况,我们枚举每一条边作为堵车的边,并标记。再跑一边dijkstra求一遍除这条堵车边的最短路,更新答案。 我们枚举每一条边作为堵车的边,
阅读全文
摘要:这是一道细节理解和处理的题目,我们需要建立坐标系,并且将每个视图中的位置正确转化成坐标系中的位置,注意每个视图是从正方体内部看到的。 为了处理每个位置有哪几种光线,我们可以将三条光线状压为三位二进制数,最后统计即可。 1 #include <iostream> 2 #include <cstdio>
阅读全文
摘要:这是一道状压dp的入门练习题 我们可以预处理出每一行国王的合法摆放方案,然后进行dp。 我们定义f[i][j][k]表示前i行,第i行的状态为j且使用了k个国王的合法方案数,那么存在 f[i][j][k]=∑f[i-1][j'][k'],其中j&j'=0,j&j'<<1=0,j&j'>>1=0 注意
阅读全文
摘要:纯搜索题 一开始思路比较混乱,但是仔细想想便能得出正解。 我们预处理出每一棵子树的大小、每一层的儿子们,之后进行一次dfs,暴力枚举删除每一棵子树,同时更新答案,同时注意标记是否删除。搜索完成后回溯。最终就能得出答案。 1 #include <bits/stdc++.h> 2 using names
阅读全文
摘要:一道关于优先队列的搜索题。 我们建立一个小根堆,将开始确定的值放进去,然后进行bfs。 对于每个点,向上下左右四个方向扩展,并且更新答案,同时将没入队的节点入队即可。 最后,我们得到了一个搜索完成的图,我们判断一下合法性,输出答案即可。 这道题有一个坑点:输入可能重复同一节点但权值不同,这种情况应当
阅读全文
摘要:贪心题,我们使用邻项交换的方法求解。 我们假设当前有两个相邻的人分别为1,2,他们的左右手的数字分别为a,b,假设1之前的人的左手的数字之积为x,那么当前的答案为 我们将这两个人的位置交换,显然,这两个人位置的交换不会影响其他的人的答案,那么交换后的答案为 我们假设以上四个数分别为k1,k2,k3,
阅读全文
摘要:dfs+dp 我们要在一个大矩阵中选出一个小矩阵使得小矩阵的分值最小 所以我们先用dfs枚举选哪些行,再在dfs选的行的基础上对列进行dp,最后更新答案即可。 具体地,我们先通过dfs枚举r行,然后计算两个数组:sum[i][j]表示在当前dfs确定的行的状态下,第i列和第j列相邻时产生的分值。s[
阅读全文
摘要:模板来源:codevs 5429 根据背包问题的相关状态转移方程,我们不难写出朴素的算法 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace s
阅读全文
摘要:本人是NOIP2017的亲历者,两年前这道题我在考场上随便打了个二分暴力,就草草结束了 如今在做这道题,便能简单的AC了 我采用的思路是二分答案,然后用dp判断答案的可行性。定义f[i]表示到i这个格子最大的分数,如果为一个极小值则可以认为这个点无法到达;x[i]表示i的位置,g表示当前二分的答案。
阅读全文
摘要:单调队列优化dp 我们将每个人的s值排序,这样我们就能保证当前这个人刷的木板一定在上一个人之后,我们就能进行线型dp 定义f[i][j]表示前i个人刷前j个木板获得的最多报仇,那么有 在dp过程中,我们假定外层变量i为定值,当j增大时,不难发现k的取值范围上界不变,下界变大。我们不妨比较一下两个决策
阅读全文
摘要:我们定义f[i][j]表示前j个数组成的长度为i的合法序列的个数,那么有 因此我们不难写出朴素dp的代码 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using nam
阅读全文
摘要:线型dp+线段树优化 我们定义f[i]表示覆盖[L,i]的最小代价,我们将牛按照r递增排列,假设当前牛为[ai,bi],代价为vali 那么存在 我们在状态转移时,每次需要查询区间内的最值,同时f数组发生更新,因此我们可以用线段树的查询、修改在较快时间内维护f数组。 同时我们注意一下边界的处理即可。
阅读全文
摘要:记忆化搜索的经典例题 一个显然的想法,直接枚举每一个点作为起点然后dfs,求出最大值。显然这种做法一定会TLE,我们不妨进行一下优化:由于每一个点会被重复搜索,我们不妨进行记忆化,当这一个点搜索完成后,我们记下从这个点出发的最优解。下次搜索到这个点时我们就可以O(1)返回答案,这样搜索效率大大提高,
阅读全文
摘要:动态维护中位数的题目。 我们采用对顶堆做法,建立一个大根堆存储前半段序列(排序后),小根堆存储后半段序列,通过维护两个堆使得他们元素个数之差不大于1 ,这样这个序列的中位数就是大根堆的堆顶。 关于如何维护对顶堆:如果两个堆元素个数差大于1,我们就把大根堆的堆顶放到小根堆当中(或是把小根堆堆顶放到大根
阅读全文
摘要:树的直径的模板题 我们存图以后,对这张图(树)进行一次dfs,定义sum1表示从当前节点向他的儿子走的最长路径是多少,sum2表示次长路径是多少。我们每次先用当前路径的长度+当前路径前往的节点的sum1更新当前节点的sum2,如果更新后sum2大于sum1,那么我们交换他们的数值,不难发现这样是正确
阅读全文
摘要:好像跟POJ重题 这是一道扫描线的题。 由于窗口的大小已知,我们不妨换一下思路,把问题转化成这样:平面内有若干个矩形(大小就是窗口的大小,矩形左下角的位置就是某一颗星星的位置),每一个矩形覆盖的区域都有一个权值(星星的亮度),求某一位置,使得这个位置被覆盖的权值最大,最大值即答案。 为什么这样就是正
阅读全文