08 2018 档案
摘要:这里的先后关系可以看成节点和父亲的关系在树里面,没有父亲肯定就没有节点所以我们可以先修的看作父亲,后修的看作节点所以这是一颗树这题和上一道题比较相似都是求树上最大点权和问题但这道题是多叉树这里有多个根,那就加一个编号为0的根,价值为0, 同时m要+1(因为这个虚拟的 ...
阅读全文
摘要:这道题一开始是按照caioj上面的方法写的(1)存储二叉树用结构体,记录左儿子和右儿子(2)把边上的权值转化到点上,离根远的点上(3)用记忆化搜索,枚举左右节点分别有多少个点,去递归这种写法有个好处, 避免了总的树枝个数的枚举#include#include#incl...
阅读全文
摘要:解这道题的前提是非常熟悉中序遍历的方式我就是因为不熟悉而没有做出来中序遍历是5 7 1 2 10的话,如果1是根节点那么5 7 1就是1的左子树,2, 10就是右子树这就有点中链式dp的味道了,实际解法也是中链式dp的解法设f[i][j]为中序遍历从i到j的最大价值f...
阅读全文
摘要:直接写暴搜,然后过了#include#define REP(i, a, b) for(int i = (a); i n) break; dfs(i + 1, j, sum + j); }}int main(){ scanf("%d%d", ...
阅读全文
摘要:刷刷水题压压惊低级版的能量项链相当于复习一次中链式dp这种合并了之后又后效性的题目都可以用类似的方法做#include#include#include#define REP(i, a, b) for(int i = (a); i < (b); i++)using na...
阅读全文
摘要:这道题用n方的算法会很好做我一开始想的是nlogn的算法求方案数,然后没有什么想法(实际上也可以做,但是我太弱了)我们就可以根据转移方程来推方案数,只是把max改成加,很多动规题都是这样,比如背包的方案数。设f[i]为以i为结尾的方案数当 b[j] + 1 == b[...
阅读全文
摘要:这真是一道好题目学到了很多一开始感觉吃或者不吃会有后效性然后看到洛谷的题解,直接把这个有后效性的部分当作dp的维度和值因为这个垃圾可以堆或者不堆,所以这个很像01背包,但是加了非常多的限制条件,是一个升级版的01背包 记住思考01背包问题的时候,要思考i那一维度,最...
阅读全文
摘要:没看出来动规怎么做,看到n #include#include#define REP(i, a, b) for(int i = (a); i #include#include#define REP(i, a, b) for(int i = (a); i = 0; i--...
阅读全文
摘要:好气,在洛谷上交就过了,在caioj上交就只有40分之前在51nod做过这道题了。https://blog.csdn.net/qq_34416123/article/details/81809024 #include#include#include#define RE...
阅读全文
摘要:记住一定要区分n和m分别代表什么,我已经因为这个两道题浪费很多时间了然后这个道题有点类似最长上升子序列n平方的做法,只是判断的条件不同而已#include#include#include#define REP(i, a, b) for(int i = (a); i =...
阅读全文
摘要:每个素数就是一个物品,然后就相当于求完全背包方案数把max改成+就好了。#include#include#include#define REP(i, a, b) for(int i = (a); i prime;ll f[MAXN];void get_prime()...
阅读全文
摘要:非常奇怪的是,我在Vijos 1071能AC,在caioj 就只有50分可以和前面一道题一样算方案,如果大于1就是多解然后就输出方案就好了#include#include#define REP(i, a, b) for(int i = (a); i = w[i]; j...
阅读全文
摘要:方程很简单f[0] = 1f[j] += f[j-w[i]]#include#define REP(i, a, b) for(int i = (a); i = w[i]; j--) f[j] += f[j-w[i]]; printf("%d\n", f[m]); ...
阅读全文
摘要:一开始看到题目感觉很难然后看到题解感觉这题贼简单,我好像想复杂了就算出每一行最少的资源(完全背包+二分)然后就枚举就好了。 #include#include#include#define REP(i, a, b) for(int i = (a); i k) sum ...
阅读全文
摘要:这道题的难点在于价值可以多。这道题我一开始用的是前面的状态推现在的状态实现比较麻烦,因为价值可以多,所以就设最大价值为题目给的最大价值乘以10#include#include#include#define REP(i, a, b) for(int i = (a); i...
阅读全文
摘要:这道题我一直按照往常的思路想f[i]为前i个任务的最大空暇时间然后想不出来怎么做……后来看了题解发现这里设的状态是时间,不是任务自己思维还是太局限了,题做得太少。很多网上题解都反着做,那么麻烦干嘛设f[i]为前i时间内的最大空暇时间。这里是更新后来的状态,和以前不一样...
阅读全文
摘要:这道题的难点在于,前面分组的时间会影响到后面的结果也就是有后效性,这样是不能用dp的所以我们要想办法取消后效性那么,我们就可以把影响加上去,也就是当前这一组加上了s那么就把s对后面的影响全部加上这个做法非常巧妙。#include#include#include#def...
阅读全文
摘要:这道题题目给的顺序不是固定的所以一开始要自己排序,按照w来排序后来只要看l就可以了然后求最长下降子序列即可(根据那个神奇的定理,LIS模板里有提到) #include#include#include#define REP(i, a, b) for(int i = (a...
阅读全文
摘要:第一问最长 不上升子序列,第二问最长上升子序列套模板就好https://blog.csdn.net/qq_34416123/article/details/81358447那个神奇的定理当作结论吧#include#include#include#define REP(...
阅读全文
摘要:f[i]表示从起点到第i个车站的最小费用f[i] = min(f[j] + dist(i, j)), j #include#define REP(i, a, b) for(int i = (a); i e) swap(s, e); REP(i, 2, n + 1) ...
阅读全文
摘要:这道题和前面的分组的题有点像就是枚举最后一组的长度。然后组数可以在第一层循环也可以在第二层循环我自己的话就统一一下在第一层循环吧然后这道题题意我一直没理解清楚,浪费了很多时间,写复杂了同时初始化的问题很重要。f[i][j]为前i格j个人分配的最大值f[0][0] = ...
阅读全文
摘要:我一开始是这么想的注意这道题数组下标是从大到小推,不是一般的从小到大推f[i]表示从最高层h到第i层所花的最短时间,答案为f[1]那么显然f[i] = f[j] + wait(j) + (j - 1), j > i也就是说枚举从哪个楼层过来。取最优wait(j)表示从...
阅读全文
摘要:出处[辗转山河弋流歌 by 空灰冰魂]blog.csdn.net/vmurder/article/details/46537613memset(a, 0x3f, sizeof(a)) //int, 到1e9左右,相加不会溢出memset(a,0xc0,sizeof(a...
阅读全文
摘要:这道题写了我好久, 交上去90分,就是死活AC不了后来发现我写的程序有根本性的错误,90分只是数据弱#include#include#define REP(i, a, b) for(int i = (a); i 0 && dp[i-1][j-t[i-1]] > dp...
阅读全文
摘要:我一开始想的是前i个区间的最大值显然对于当前的区间,有不选和选两种情况如果不选的话,就继承f[i-1]如果选的话,找离当前区间最近的区间取最优f[i] = max(f[i-1, f[j] + a[i].v()) j为i前面区间中能取得离i最近的区间那么显然这里涉及到f...
阅读全文
摘要:首先可以看出排序之后,最优解肯定是每一对都相邻才是最优的那么我们就要找构成最优解的相邻组设f[i][j]是前i个字符,k对的最小值如果当前这个筷子不取的话,f[i][j] = f[i-1][j]如果取的话 f[i][j] = f[i-2][j-1] + (a[i]-a...
阅读全文
摘要:一开始写了一个复杂度很大的方法,然后还过了(千万记得开longlong )#include#include#include#define REP(i, a, b) for(int i = (a); i #include#include#define REP(i, a,...
阅读全文
摘要:我又总结了一种动归模型……这道题和上一道题很类似,都是给一个序列,然后相邻的元素可以合并然后合并后的元素可以再次合并那么就可以用这两道题类似的方法解决 简单来说就是枚举区间,然后枚举断点加上断点左右两边的值(按照题目,可能不是加),然后在按题目加上计算合并后总的序列的...
阅读全文
摘要:经典的石子合并问题!!!设f[i][j]为从i到j的最大值然后我们先枚举区间大小,然后枚举起点终点来更新f[i][j] = min(f[i][k] + f[k+1][j] + sum(i, j));最后f[1][n]就是答案!!#include#include#inc...
阅读全文
摘要:三维的与二维大同小异,看代码。#include#include#include#define REP(i, a, b) for(int i = (a); i < (b); i++)using namespace std;const int MAXN = 112;cha...
阅读全文
摘要:在51nod刷到过同样的题,直接秒杀见https://blog.csdn.net/qq_34416123/article/details/81697683#include#include#include#define REP(i, a, b) for(int i = ...
阅读全文
摘要:复制上一题总结caioj 1069到1071 都是最长公共字序列的拓展,我总结出了一个模型,屡试不爽 (1) 字符串下标从1开始,因为0用来表示字符为空的情况,而不是第一个字符 (2)初始化问题。 一般设f[i][j]为第一个字符前i个,第二...
阅读全文
摘要:复制上一题总结caioj 1069到1071 都是最长公共字序列的拓展,我总结出了一个模型,屡试不爽 (1) 字符串下标从1开始,因为0用来表示字符为空的情况,而不是第一个字符 (2)初始化问题。 一般设f[i][j]为第一个字符前i个,第二...
阅读全文
摘要:caioj 1068是最长公共子序列裸体,秒过, 就不写博客了caioj 1069到1071 都是最长公共字序列的拓展,我总结出了一个模型,屡试不爽 (1) 字符串下标从1开始,因为0用来表示字符为空的情况,而不是第一个字符 (2)初始化问题。 ...
阅读全文
摘要:因为这里涉及到乘号的个数,那么我们可以用f[i][j]表示前i个位乘号为j个时的最大乘积那么相比上一题就是多了一层枚举多少个乘号的循环,可以得出f[i][r] = max(f[j - 1][r - 1], num(j, i));num(j, i)表示第j位到第i位的数...
阅读全文
摘要:很容易想到f[i]为前i项的最优价值,但是我一直在纠结如果重量满了该怎么办。正解有点枚举的味道。就是枚举当前这辆车与这辆车以前的组合一组,在能组的里面取最优的。然后要记得初始化,因为有min,所以除0外初始化为最大,f[0] = 0这实际上可以抽象出一种模型,就是一个...
阅读全文
摘要:就是最长上升子序列,但是要用n^2的算法。#include#include#define REP(i, a, b) for(int i = (a); i a[j]) b1[i] = max(b1[i], b1[j] + 1); } for(int i = n ...
阅读全文
摘要:这道题一开始我是这么想的最后的答案肯定是某次的马克换回来的,但这个该怎么确定??实际上应该把范围缩小,只看最后一次和倒数第二次之间有什么联系。可以发现,只有两种可能,最后一天换或者不换。换的话就要求出最后一天之前最多的马克,不换的话就是最后一天前最多的美元。设d[i]...
阅读全文
摘要:这道题的分析方法我很需要学习学习。一开始我想的是f[i][j]表示前i个数子序列长度为j的个数然后发现新加入一个数的时候会和前面的重复,这个时候不知道该怎么处理这种重复。其实我再继续往下想就可以想到,这些重复的序列都有一个特征,结尾都是新加入的这个数那么这就启示我们可...
阅读全文
摘要:这里要求要走到终点再走回来,可以转化为两个人走。那么我们可以先粗暴的设f[x1][y1][x2][y2]为第一个人走到(x1, y1), 第二个人走到(x2, y2)的最大价值。那么这样空间会很大,通过观察可以发现,一个走的步数=横坐标+纵坐标,因为走一步一定是横坐标...
阅读全文
摘要:有N种物品,每种物品的数量为C1,C2......Cn。从中任选若干件放在容量为W的背包里,每种物品的体积为W1,W2......Wn(Wi为整数),与之相对应的价值为P1,P2......Pn(Pi为整数)。求背包能够容纳的最大价值。我们可以转化成01背包来做,但是...
阅读全文
摘要:这个问题就是在原来的基础上加上了可以循环。那么我们可以分两种情况处理,一种是有从尾到头的,例如1表示取,0表示不取,则是11000011一种是没有跨越的, 即000111100那么对于第二种情况可以直接用最大字段和做,关键是第一段要怎么处理。这里需要用到逆向思维,在1...
阅读全文
摘要:将一堆正整数分为2组,要求2组的和相差最小。显然我们可以把所有可能组合成的数求出来。然后从总和的中间开始往大找,找到了就是其中一个的分组,就可以求出答案了。#include#include#define REP(i, a, b) for(int i = (a); i ...
阅读全文
摘要:#include#include#define REP(i, a, b) for(int i = (a); i = w; j--) f[j] = max(f[j], f[j - w] + v); } printf("%d\n", f[m]); return 0;...
阅读全文
摘要:给出一个整数数组a(正负数都有),如何找出一个连续子数组(可以一个都不取,那么结果为0),使得其中的和最大?用f[i]表示以i为结尾的最大字段和,也就是说i一定要取,那么f[i] = max(a[i], f[i-1] + a[i])只有两种选择,之前的一段取或者不取。...
阅读全文
摘要:一个N*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,从左上走到右下,只能向下向右走,求能够获得的最大价值。f[i][j] = max(f[i-1][j], f[i][j-1]) + a[i][j];边界: f[i][0] = 0; f[0][i] =...
阅读全文
摘要:一个M*N的矩阵,找到此矩阵的一个子矩阵,并且这个子矩阵的元素的和是最大的,输出这个最大的值。我们可以降维,枚举矩形的长,然后算出一个一维数组,然后就转化成了最大字段和问题#include#include#define REP(i, a, b) for(int i =...
阅读全文
摘要:这道题一开始觉得增加和删除会移动字符串的位置很不好做两个字符串dp状态一般是第一个前i个和第二个前j个#include#include#include#define REP(i, a, b) for(int i = (a); i #include#include#de...
阅读全文
摘要:当x = 0 或 y = 0时 f[x][y] = 0当a[x] = b[y]时 f[x][y] = f[x-1][y-1]+1当a[x] != b[y]时 f[x][y] = max(f[x][y-1], f[x-1][y])注意这里字符串要从1开始,因为转移方程...
阅读全文
摘要:这道题有个初始值设成1e9, 然后这个值是要加很多次的,然后就会溢出变成负数,然后就一直WA, 找这个bug找了一个小时……以后不能随便这样设那么大,要考虑会不会加很多次然后溢出。讲一下思路。首先对于当前节点u,可以分三种情况。一种是当前节点是服务器,一种是节点的父亲...
阅读全文
摘要:这里的状态定义的非常的巧妙,d(i, 1)表示以i为根节点且选i的子树的最大独立子集d(i, 0)表示以i为根节点且不选i的子树的最大独立子集d(i, 1) = sum{ d(v, 0) | v是i的儿子}d(i, 0) = sum{ max(d(v, 0), d(v...
阅读全文
摘要:这道题还是比较简单的,对于当前节点,算出每个儿子需要的人数然后再算出当前节点需要多少个人数,然后排个序加上去就好了。#include#include #include#define REP(i, a, b) for(int i = (a); i son[MAXN];...
阅读全文
摘要:设置f(i, j)为点i, i + 1 ……j所组成的多边形。那么可以枚举中间点k, 得f(i, j) = min{s(i, j, k), f(i, k), f(k, j) | i #include#include#include#define REP(i, a, b...
阅读全文
摘要:当前区间f(i, j)分两种情况,一种是s[i]于s[j]符合要求,那么可以转移到f[i + 1][j - 1] 这样答案只会更小或者相等第二种是直接分成两个部分, 即f[i][j] = f[i][k] + f[k + 1][j],这个时候要取min同时要注意第一种情...
阅读全文
摘要:区间dp,可以以一个区间为状态,f[i][j]是第i个切点到第j个切点的木棍的最小费用那么对于当前这一个区间,枚举切点k,可以得出f[i][j] = min{dp(i, k) + dp(k, j) | i #include#include#define REP(i, ...
阅读全文
摘要:这题看题解看了很久,学到了挺多(自己还是太弱,唉!)(1)这道题的思路非常的巧妙。我一开始看到就觉得不好来记录开始位置以及结束位置。但是题解换了一个思路,记录每一次开始了但还没有结束的字符有多少个这样每次进来一个新的字符,就可以更新答案。(2)这一类两个字符串取公共部...
阅读全文
摘要:这道题判断回文串的方法非常的秀!这里用到了记忆化搜索,因为会有很多重复同时用kase来区分每一组数据然后还有用递归来判断回文,很简洁然后这种线性结构的动态规划的题,就是把当前的这个数组分成两块来枚举,一块是之前已经得出的最优解,一块是自己现在按照题目要求来算出的值,这...
阅读全文
摘要:这道题的下标从1开始比较方便,一方面前缀和算的方便一些,一方面涉及到前j个灯泡,那么如果从0开始,前3个灯泡就是第0, 1, 2, 3个,非常奇怪。所以灵活换下标。然后这道题的动规有点暴力枚举的意思,在算出前面答案的前提下枚举当前灯泡用多少去更新当前答案#includ...
阅读全文
摘要:参考https://www.cnblogs.com/yuelian/p/8745807.html注意最长上升子序列用lower_bound,最长不下降子序列用upper_bound比如123458, 加入了5假设求最长上升子序列这个时候只能替换5,不能替换8(严格上升...
阅读全文
摘要:总的来说就是价值为1,时间因物品而变,同时注意要刚好取到的01背包(1)时间方面。按照题意,每首歌的时间最多为t + w - 1,这里要注意。同时记得最后要加入时间为678的一首歌曲(2)这里因为要输出时间,也就是重量,那么这个时候初始化就要注意了。因为如果只是输出价...
阅读全文
摘要:这道题在递推方式和那个数字三角形有一点相像,很容易推出来但是这道题要求的是字典序,这里就有一个递推顺序的问题这里用逆推,顺推会很麻烦,为什么呢?如果顺推的话,最后一行假设有种情况是最小值,那么你怎么知道哪一种的是字典序最小?最后一行的数字最小显然不一定整个路径的字典序...
阅读全文
摘要:首先做一个转化,这种转化很常见。题目里面讲要来回走一遍,所以就转化成两个从起点到终点,路径不重合那么很容易想到用f[i][j]表示第一个走到i,第二个人走到j还需要走的距离但是这里无法保证路径不重合,所以这里怎么设计状态很关键。我们设f[i][j]是1到max(i, ...
阅读全文
摘要:很明显可以根据放不放建边,然后最一遍最长路即是答案DAG上的动态规划就是根据题目中的二元关系来建一个DAG,然后跑一遍最长路和最短路就是答案,可以用记忆化搜索的方式来实现细节:(1)注意初始化数组 (2)搜索的过程中最后记住加入状态本身的值,不然会...
阅读全文
摘要:影响到状态的只有时间和在哪个车站(空间),所以可以设f[i][j]是时刻i的时候在第j个车站的最少等待时间因为题目中的等待时间显然是在0时刻1车站,所以答案为f[0][1],那么就提醒我们从大推到小,然后可以发现d[T][n]一定等于0,所以这个可以作为边界条件。同时...
阅读全文

浙公网安备 33010602011771号