codeforces的dp专题
个人在codeforces上的dp类型题目的专题训练
黎辰
其实一切只为一个理由,一切理由在一个人面前也都沦为借口
展开
-
codeforces 494B B. Obsessive String(dp)
题目链接:codeforces 494B题目大意:给出两个字符串,问第一个字符串由多少种方法提取出一些子串使这些子串中都包含t模式串。题目分析:定义状态dp[i]表示前i个字符由多少种方法得到符合要求的字符串组。dp[i]=dp[i−1]+∑j=0l−1dp[j]+ldp[i] = dp[i-1] + \sum_{j=0}^{l-1}dp[j] + l解释: 首先dp[i-1]代表的是不重新原创 2015-10-07 10:43:34 · 2892 阅读 · 0 评论 -
codeforces 486D D. Valid Sets(树形dp)
题目链接:codeforces 486D题目大意:给出一棵树,求这棵树的满足最大点与最小点之差小于d的连通子图的个数。题目分析:因为涉及到图中的最大点和最小点,所以我们先枚举一个点作为最大点,然后搜比它小的与它连通的点进行dp对于每个与它相邻不比它大的点有两种情况,不选这个点的话,那么只有一种情况,因为所选的子图必须是连通的,如果不选这个点,那么它的子树中的点都不选,如果选这个点,那么递归地考虑原创 2015-10-06 19:01:11 · 2060 阅读 · 0 评论 -
codeforces 372B B. Counting Rectangles is Fun(暴力)
题目链接:codeforces 372B题目大意:给出一个01矩阵,每次询问给出一个范围,问这个范围当中的全0矩阵的个数。题目分析:首先做一个预处理,处理出sum[i][j][k][t]也就是在以(i,j)为左上角的矩阵中以(k,t)为右下角能够得到的阶梯的最大面积。(因为阶梯状能够保证每个点都可以作为左上角得到一个矩形)暴力求取即可然后每次查询,枚举右下角,然后求和即可。 AC代码:#inc原创 2015-10-06 16:10:15 · 1023 阅读 · 0 评论 -
codeforces 402D D. Upgrading Array(dp+数论)
题目链接:codeforces 402D题目大意:给出一个数列,可以进行一种操作将某一个前缀除去他们的gcd,有一个函数f(x),f(1) = 0 , f(x) = f(x/p)+1,f(x) = f(x/p)-1(p是坏素数)问 ∑i≤nf(a[i])\sum_{i \leq n} f(a[i] )的最大值题目分析:首先根据那个递推式我们知道结果就是每个数的f(x)就是它的质因数当中的好素数的个原创 2015-10-06 14:22:31 · 1948 阅读 · 0 评论 -
codeforces 432D D . Prefixes and Suffixes(后缀数组)
题目链接:codeforces 432D题目大意:给出一个字符串,求有多少种长度的前缀和后缀相等,并且得到的这个子串在原字符串中出现的次数。题目分析:首先利用后缀数组处理出sa[i]代表排名第i位的后缀的起始位置处理出rank[i]代表第i个位置起始的后缀的rank处理出height[i]代表排名第i位的和排名i-1位的公共前缀的长度。那么我们要找后缀和前缀相等的就是找到rank[0],然后原创 2015-10-06 10:08:49 · 2105 阅读 · 0 评论 -
codeforces 571B B. Minimization(dp)
题目链接:codeforces 571B题目大意:给出一个序列,可以任意调整序列的顺序,使得给出的式子的值最小 ∑k=1n−k|ai−ai+k|\sum_{k=1}^{n-k} | a_i - a_{i+k}|题目分析:我们知道通过递增k可以得到一条链,那么我们就能够得到n%k条长度为n/k+1的链,得到k-n%k条长度为n/k的链,因为链上相邻的元素都会有一个差,这个差之和是an−a1a_n-原创 2015-10-05 21:43:02 · 2857 阅读 · 0 评论 -
codeforces 583B B. Once Again...(dp)
题目链接:codeforces 583B题目大意:给出一个序列,是由一个长度为n的序列复制T次得到的,问最长子序列的长度。题目分析:我们可以暴力的做n*n内的部分,得到这部分的最长不降子序列。我们可以知道如果通过选取递减的可以得到更好的结果,那么在这之中一定已经选过,就算每次下降都能得到更好的结果,那么n次下降也能保证后面添加的全部都是只加入相同的元素,所以我们找到出现次数最多的元素,然后加入这原创 2015-10-05 20:07:19 · 2082 阅读 · 0 评论 -
codeforces 487B B. Strip(rmq+线段树+二分)
题目链接:codeforces 487B题目大意:给出一个序列,要把序列划分成段,每一段最少有L个元素,段中的最大元素和最小元素之差不大于s,问划分的段的最少的数量是多少。题目分析:首先用rmq维护区间最大值和区间最小值。然后按顺序扫描数组,线段树维护的数组,每个记录当前点作为最后一个点的前i个点划分的最小的段数,那么每次更新就是二分找到可以转移到我的最远距离,然后再选取与我距离大于l的那部分,原创 2015-10-05 16:13:39 · 1605 阅读 · 0 评论 -
codeforces 351B B. Jeff and Furik(概率)
题目链接:codeforces 351B题目大意:给出一个游戏,先手选择一对相邻的数交换位置,后手随机找一对数,然后掷硬币决定是否交换,如果不能交换,那么就重新找。问大致序列有序的采取最优策略的布数的期望。题目分析:定义dp[i]表示减少i个逆序对的步数的期望。dp[i]=1+1+dp[i−2]⋅0.5+dp[i−1+1]]⋅0.5dp[i] = 1+1 + dp[i-2] \cdot 0.5原创 2015-10-05 11:34:10 · 1631 阅读 · 0 评论 -
codeforces 245H H. Queries for Number of Palindromes(区间dp)
题目链接:codeforces 245H题目大意:给出一个字符串,询问任意区间内的回文子串的个数。题目分析:定义isPar[i][j]表示区间字符串[i,j]是否是回文,可以通过isPar[i+1][j-1]递推得到。定义dp[i][j]表示及区间[i,j]内的回文子串的个数,转移方程如下:dp[i][j]=dp[i+1][j]+dp[i][j−1]−dp[i+1][j−1]+isPar[i][原创 2015-10-05 09:44:49 · 1358 阅读 · 0 评论 -
codeforces 158E. Phone Talks(dp)
题目链接:codeforces 158E题目大意:给出一些电话,有打进来的时间和持续的时间,如果人在打电话,那么新打进来的电话入队,如果人没有打电话,那么人必须立即接电话,或者选择一次放弃的机会,问这个最多有多长的连续的空闲的时间。题目分析:定义状态dp[i][j]表示接到第i个电话在放弃j次的情况下最少需要多长时间。转移方程很简单:dp[i][j]=min(max(dp[i−1][j]+di,原创 2015-10-04 20:37:36 · 1474 阅读 · 3 评论 -
codeforces 163A A. Substring and Subsequence(dp)
题目链接:codeforces 163A题目大意:给出两个字符串,求第一个字符串的子串和第二个字符串的子序列相等的个数。题目分析:定义状态dp[i][j]表示s的子串以i结尾,t的子序列以j结尾的相等的对数。转移方程很简单,就是当某一位上两个字符相等的时候,dp[i][j]=∑k<jdp[i−1][k]dp[i][j] = \sum_{k<j} dp[i-1][k] AC代码:#include原创 2015-10-04 19:13:29 · 1023 阅读 · 0 评论 -
codeforces 22B B. Bargaining Table(dp)
题目链接:codeforces 22B题目大意:给出一个矩阵,求周长最大的矩形的周长题目分析:求出每个点为底的最大的高度(0),然后枚举右下角,再枚举矩形的高度,然后算取长度,进而算取周长即可。AC代码:#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#define MAX 30using n原创 2015-10-04 16:27:50 · 1372 阅读 · 0 评论 -
codeforces 358D D. Dima and Hares(dp)
题目分析:codeoforces 358D题目大意:给出n个数,每个数取走的贡献与相邻的数有关,如果取这个数的时候,左右的数都还没被取,那么权值为a,如果左右两个数有一个被取走了,那么权值为b,如果左右两个数都被取走了,那么权值为c,求取取走全部数的最大值。题目分析:定义状态: dp[i][1][0]表示选第i时,相邻的数有一个被取走,这个数在当前数左侧。dp[i][1][1]表示选第i时,相原创 2015-10-04 15:29:03 · 1586 阅读 · 0 评论 -
codeforces 366C C. Dima and Salad(dp)
题目链接:codeforces 366C题目大意:给出n个物品,有两个属性,问最后第一个属性的总和是第二个属性的k倍的时候,第一个属性最大是多少。题目分析:我们将物品做一个变形,重量为a[i]-b[i]*k,收益是a,那么我们只需要对重量为正的做一遍背包,对质量为负的取绝对值做一遍背包,然后重量相等的背包的收益之和就是当前重量下的最大收益. AC代码:#include <iostream>#in原创 2015-10-04 09:41:58 · 2121 阅读 · 1 评论 -
codeforces 337D D. Book of Evil(树形dp)
题目链接:codeforces 337D题目大意:给出一棵树,给出感染物的感染范围,给出一些已经确定被感染的点,问感染物可能放置的点的个数。题目分析:定义状态dp[i]代表某个点到达离它最远的确定的感染点的距离。然后我们首先dfs一遍,求得以1为根的树,每个点到子树中的感染点的最大距离,然后再dfs一遍,求得dp[i]所要求的值,利用一个dd[i]数组表示第i点的父亲,除了自己及以自己为根的子树原创 2015-10-03 20:50:28 · 1991 阅读 · 0 评论 -
codeforces 180C C. Letter(dp)
题目链接:codeforces 180C题目大意:给出一个字符串,问最少修改多少个字符,能够得到一个前面是大写,后面是小写的字符串。题目分析:定义状态dp[i][0]表示当前位是大写,得到合法状态的最小花费。定义状态dp[i][1]表示当前位是小写,得到合法状态的最小花费。转移方程很简单,具体看代码。 AC代码:#include <iostream>#include <cstdio>#in原创 2015-10-03 16:47:07 · 1375 阅读 · 0 评论 -
codeforces 455C C. Civilization(树形dp+树的直径+并查集)
题目链接:codeforces 455C题目大意:给出一些点,他们之间初始存在一些边,给出两种操作,第一种是查询某个点所在的树的直径,另一种是将两个树合并,要求使合并后的树的直径最小。题目分析:首先算取没做操作前的连通块里的树的直径,也就是先dfs一遍,找到深度最大的点,然后从这个点再搜,找到的最远的距离就是这棵树的直径,因为可以证明从根搜深度最大的点一定是树的直径的一个端点,因为它可以通过到达次原创 2015-10-03 16:30:06 · 2488 阅读 · 0 评论 -
codeforces 453B B. Little Pony and Harmony Chest(dp+数论)
题目链接:codeforces 453B题目大意:给出一个序列a,求取一个序列b,b序列的数两两互质,问能够导致∑|ai−bi|\sum | a_i - b_i|最小的方案题目分析:定义状态dp[i][j]表示前i个数达到j状态的最小的结果,j状态表示已经被用过的质数。因为当一个a的数据范围不超过30,所以如果某个数超过60,那么选择1一定比它更优,所以我们能够用到的数的质因子也一定不会超过60原创 2015-10-03 14:50:26 · 2007 阅读 · 0 评论 -
codeforces 459E E. Pashmak and Graph(dp)
题目链接:codeforces 459E题目大意:给出n个点,m条边的有向图,每个边有边权,求一条最长的边权上升的路径的长度。题目分析:定义dp[i]表示第i条边结尾的情况下的最长路径。定义g[i]表示点i结尾的情况的最长路径。对所有的边进行排序,那么前面的边只可能小于等于后面的边。所以dp[i] = g[e[i].u]+1 然后只需要特殊考虑一下边相等的情况,更新g[i]即可,具体见代码原创 2015-10-03 10:51:34 · 1868 阅读 · 0 评论 -
codeforces B. Cow Program (记忆化搜索)
题目链接:codeforces 283B题目大意:给出n个数,奇数次操作x,y都加上a[x],偶数次操作y加上a[x],x减去a[x],走出了范围就结束。 问结束时的y值,如果无法结束,那么输出-1题目分析:记录状态dp[x][2]为在奇数次或偶数次到达x点时走完还会获得的权值。直接搜索,搜索到搜过的状态直接返回。 AC代码:#include <iostream>#include <cstd原创 2015-10-01 16:13:57 · 1370 阅读 · 0 评论 -
codeforces 478D D. Red-Green Towers(dp)
题目链接:codeforces 478D题目大意:给出r个红砖,g个绿砖,问有多少种方法搭成最高的塔。题目分析:定义状态dp[i][j]表示构造i层的塔需要j块绿砖的方案数。转移方程:dp[i][j]=dp[i−1][j−i]+dp[i−1][j]dp[i][j] = dp[i-1][j-i] + dp[i-1][j]分别代表当前这一层放绿砖还是放红砖(当然要先判断当前状态转移是否合法) AC原创 2015-10-02 10:01:41 · 1795 阅读 · 0 评论 -
codeforces 461B B. Appleman and Tree(树形dp)
题目链接:codeforces 461B题目大意:给出一棵树,每个点是白色或者黑色,问有多少种方案能够通过去掉一些边使每个联通块中只有一个黑色的点。题目分析:定义状态dp[i][0…1]表示点i在以点i为根的子树中去掉边后点i所在的联通块有黑点(1)和没有黑点(0)的方案数。那么我们对于点u,首先考虑它的颜色,如果是黑色,那么dp[i][1] = 1 , 否则d原创 2015-09-24 13:23:02 · 2778 阅读 · 0 评论 -
codeforces 191A A. Dynasty Puzzles(dp)
题目链接:codeforces 191A题目大意:给出n个字符串,两个字符串如果前一个的尾与后一个的首相同,那么可以相连,最后得到的字符串要满足首尾相同,问最长的符合要求的字符串的长度是多少。题目分析:定义状态dp[i][j]代表以i开头以j结尾的最长的字符串的长度,具体转移看代码,水题不解释。 AC代码:#include <iostream>#include <cstring>#includ原创 2015-09-23 10:32:49 · 1233 阅读 · 0 评论 -
codeforces 219D D. Choosing Capital for Treeland(树形dp)
题目连接:codeforces 219D题目大意:给出一棵树,但是它的边是有向边,选择一个城市,问最少调整多少条边的方向能使一个选中城市可以到达所有的点,输出最小的调整的边数,和对应的点。题目分析:定义dp[u]为以u为根的子树中要使根都可达,需要调换方向的边的条数。定义dir[v]记录点v到父亲节点的边的方向。然后就是将每个点提成根的操作了。dp[u]换成新的定义,以u为根的到达整棵树需要原创 2015-09-23 10:28:23 · 2064 阅读 · 0 评论 -
codeforces 148D D. Bag of mice(概率dp)
题目链接:codeforces 148D题目大意:给出w只白老鼠,b只黑老鼠,公主和龙轮流取老鼠,公主先手,龙取老鼠时会吓跑一只老鼠,先取出白老鼠的人赢,如果没人取到白老鼠,那么龙赢。问公主赢的概率。题目分析:首先定义状态dp[i][j]表示第i次取老鼠时剩余黑老鼠为j的概率。那么最后结果就是∑i为奇数∑j=0bdp[i][j]\sum_{i为奇数}\sum_{j=0}^bdp[i][j]那么原创 2015-09-22 21:29:29 · 1221 阅读 · 0 评论 -
codeforces 255C C. Almost Arithmetical Progression(dp)
题目链接:codeforces 255C题目大意:给出一个序列,求最长的子序列,满足隔位的两个数相等,问这个最长的子序列的长度是多少。题目分析:定义状态dp[i][j]代表以第i个数为末尾,第j个数为倒数第二个的情况下的最长子序列。转移的方法很简单:dp[i][j]=dp[j][k]+1(a[k]==a[i])dp[i][j] = dp[j][k] +1 (a[k] == a[i])其中k的找原创 2015-09-22 19:39:26 · 1471 阅读 · 0 评论 -
codeforces 505C C. Mr. Kitayuta, the Treasure Hunter (dp)
题目链接:codeforces 255C题目大意:给出30000个岛,有n个宝石分布在上面,第一步到d位置,每次走的距离与上一步的差距不大于1,问走完一路最多捡到多少块宝石。题目分析:首先容易想到最暴力的方法:定义状态dp[i][j]代表到达i位置上一步的大小是j的情况下最多捡到的宝石数。按照题意模拟即可但是这样在时间和空间上都是不被允许的机智的人会发现,因为只有30000个点,所以步幅的原创 2015-09-22 18:31:06 · 1488 阅读 · 0 评论 -
codeforces 294B B. Shaass and Bookshelf(dp)
题目链接:codeforces 294B题目大意:给出n本书,每本书有长和宽,先立着放一排,然后在顶上再倒着放,问立着放的这一排最短的距离是多少。题目分析:定义状态dp[i][j][k]表示第i本书构成立着排长度为j,横着的排长度为k的情况是否存在。转移方程很简单,见代码。 AC代码:#include <iostream>#include <cstring>#include <cstdio>原创 2015-09-22 17:22:33 · 1251 阅读 · 0 评论 -
codeforces 375B B. Maximum Submatrix 2(dp)
题目链接:codeforces 375B题目大意:给出一个01矩阵,行与行之间可以互换位置,问能够得到最大的全1矩阵的面积。题目分析:我们有一种模型,就是对于不互换行的01矩阵求最大面积,就是固定子矩阵的右下角,记录h[i][j]就是当前位置的高度,然后向左延展的距离,枚举所有的即可。代码如下:#include <iostream>#include <cstring>#include <c原创 2015-09-22 11:08:43 · 1726 阅读 · 2 评论 -
codeforces 455B(博弈+dp)
题目链接:codeforces 455B题目大意:给出n个字符串,进行k次游戏,每次游戏输家下次作为先手,游戏规则为每次放一个字母,导致当前构造的字符串是给定的任意一个字符串的前缀,不能操作时为输,赢得第k次比赛的人会取得最终的胜利,问两人都采取最优策略的情况下,谁会赢得比赛。题目分析:首先针对这种字符串的问题我们很容易会想到利用字典树来解决,方便多模式匹配。然后我们就能想到,这其实就是一个在树原创 2015-09-22 10:01:19 · 1838 阅读 · 0 评论 -
codeforces 269B B. Greenhouse Effect(dp)
题目链接:codeforces题目大意:给出一个实数轴,上面散布着n个点,他们是m种,问最少挪多少步能将数轴上的点分成1~m的种类顺序排列的m块。题目分析:首先我们能够知道,一定存在策略将某个点一次就放到它应该放的位置。所以对于我们要动位置的植物,我们最多对于每个植物只需要动一次,定义状态dp[i]代表前i个植物,要保证升序的情况下最多保留的植物的个数。转移方程很明显,dp[i]=max{dp原创 2015-09-22 08:19:09 · 1556 阅读 · 0 评论 -
codeforces 463D D. Gargari and Permutations(dp)
题目链接:codeforces 463D题目大意:给出k个排列,问这k个排列的最长公共子序列的长度。题目分析:第一次做这种排列的dp,感觉学到了一种新的定义状态的方法。首先我们要记录pos[i][j]代表第i行数j出现的位置。cnt[i]记录当前扫过的范围内数i出现的次数 。dp[i]表示以数i结尾的最长公共子序列的长度。我们首先遍历的是序列的长度,然后每次扫描每一行上的数,更新cnt[i原创 2015-09-21 19:02:48 · 1433 阅读 · 0 评论 -
codeforces 479E E. Riding in a Lift(dp+段修改的优化)
题目链接:codeforces 479E题目大意:给出一栋n层的楼,初始在a层,b层不能去,每次走的距离必须小于当前位置到b的距离,问用电梯来回乱跑得到的序列有多少种。题目分析:定义状态dp[i][j]表示第i次乱跑跑到了j的方案数。定义dis等于|j-b|那么我们每次转移dp[i][j]能够转移到[j-dis,j+dis]但是我们要把当前位置去掉,也就是修改两段,我们采取段首加值,段尾减值原创 2015-09-21 14:45:37 · 1266 阅读 · 0 评论 -
codeforces 577B B. Modulo Sum(背包+dp)
题目链接:codeforces 577B题目大意:给出n个数,求是否存在一个子集,这个子集中的数的和能够整除m题目分析:定义状态dp[i][j]代表利用前i个数是否能够得到对m取模得j。转移的过程采取背包的方法,很水但是直接做一定会超时,O(n⋅m)\mathcal{O}(n \cdot m)利用鸽巢定理可以知道,当n>m时,有n个数便有n个前缀和,而n%m只有m-1个值,所以至少有两个余数原创 2015-09-21 13:17:47 · 2221 阅读 · 0 评论 -
codeforces 274B B. Zero Tree(树形dp)
题目链接:codeforces题目大意:给出一棵树,每个点有权值,每次操作可以对一个联通子集中的点全部加1,或者全部减1,且每次操作必须包含点1,问最少通过多少次操作可以让整棵树每个点的权值变为0.题目分析:定义状态up[u],down[u]代表点u被加操作的次数和点u被减操作的次数因为必须包含点1,所以我们将树的根定在点1,那么对于每一点的子树中点,如果要修改的话,那么一定会经过当前这个点,因原创 2015-09-21 10:26:08 · 2230 阅读 · 0 评论 -
codeforces 5C C. Longest Regular Bracket Sequence(dp)
题目链接:codeforces 5C题目大意:给出一个括号的序列,求最长的合法的子序列。题目分析:定义dp[i]表示第i个位置的右括号结尾的合法序列的左边界定义lef[i]表示第i个位置的右括号匹配到的左括号的位置利用栈进行模拟,可以得到lef[i],dp[i]的转移方程如下:dp[i]=dp[lef[i]−1](s[lef[i]−1]==′)′)dp[i] = dp[lef[i]-1](s[原创 2015-09-20 20:15:11 · 1374 阅读 · 0 评论 -
codeforces 416C C. Booking System(贪心)
题目链接:codeforces 416C题目大意:给出n个请求,每个请求包括客人数量和支付金额,再给出m个桌子,包括桌子大小,问如何安排才能最大盈利。给出最大盈利和一个能够最大盈利的方案。题目分析:采取如下的贪心策略,首先将请求按照支付金额从大到小排序,如果支付金额相同,按照人数从小到大排序,然后我们选取桌子中符合要求最小的桌子,这样就能得到最优方案。那么对于我们选取的这张桌子,是我们选取当前请原创 2015-09-18 14:53:10 · 1501 阅读 · 0 评论 -
codeforces 295B B. Greg and Graph(floyd+dp)
题目链接:codeforces 295B题目大意:给出n个点的完全有权有向图,每次删去一个点,求每次操作前整张图各个点的最短路之和。题目分析:首先删边对于我们来说是不好做的,所以我们想到了通过加点的方式逆向地做,那么加点怎么做呢?其实就是一个我们很熟悉的算法:floyd,因为我们通常用的都是它的简化版本,所以可能很多人并不理解它的确切的思想。在介绍这道题的具体解法之前,我先解释一下floyd,原创 2015-09-18 11:53:42 · 1961 阅读 · 1 评论 -
codeforces 279C C. Ladder(rmq+预处理)
题目连接:codeforces 279C题目大意:给出一个序列,m次查询,每次给出一个子串,问这个子串是否满足,中间能够找到一个元素,让这个元素作为前后分别单调的分界.题目分析:首先对于每次查询,我们知道分界一定是最大的元素,所以我们可以用rmq预处理出区间最大。然后为了判断这个区间是否能够通过最大的元素作为分界点而前后单调,我们可以通过预处理,正向和反向分别扫一遍,记录某一个点的为最大元素的能原创 2015-09-17 10:42:49 · 1856 阅读 · 0 评论