大坑!Codeforce DP题总结(持续更新)

来源:互联网 发布:会计核算软件包括哪些 编辑:程序博客网 时间:2024/05/01 05:47

个人非常喜欢做DP题,因为DP题有着特殊的数学美感持续不断吸引着我,不过最近因为事情繁忙,故好长时间没有刷DP题了,现在空下来,是时候重操旧业了,就从Codeforce上的题入手,至于为什么选这上面的题,因为目前DP题的走向趋向于状态方程极度隐蔽化!!! 而Codeforce上的题向来以巧妙著称,DP题就更是妙上加妙,所以感觉刷这DP的题能让人更上时代。


467C  George and Job

题目描述:

http://codeforces.com/problemset/problem/467/C

大致思路:

dp[i][j]代表前i个数中拿了j次m个数的最优情况,dp[i][j]=max(dp[i][j],dp[i-1][j-1],dp[i-m][j-1]+sum(i)-sum(i-m)); 5000*5000从空间上来说浪费太多,故用滚动数组更好,细节自己处理一下。

参考代码:

http://codeforces.com/contest/467/submission/7836144


466D Increase Sequence

题目描述:

http://codeforces.com/problemset/problem/466/D

大致思路:

dp[i][j]表示前i个数中还留有j个右开区间时的最优情况,dp[n][0]就是最终答案,然后考虑到i到i+1的情况,当且仅当i的右开区间等于h-a[i+1]或h-a[i+1]-1时有解,分类情况讨论一下,即可得出状态转移方程。

参考代码:

http://codeforces.com/contest/466/submission/7910930


463D Gargari and Permutations

题目描述:

http://codeforces.com/problemset/problem/463/D

大致思路:

神奇的DP思想,解题关键在于每个序列的数仅有1-n,dp[i]代表第一个序列中的前i个数在其他序列中的最长公共序列,然后对每个序列记录数字1-n出现的位置,i到i+1的时候,判断其他序列中a[1][1..i]这些数字中有多少数字的位置刚好也在本序列的a[1][i+1]这个数字位置之前,至于这些之前数字的排列所构成的最有情况,dp[i]已经算过了,所以可以直接用。

参考代码:

http://codeforces.com/contest/463/submission/7910608


461B Appleman and Tree

题目描述:

http://codeforces.com/problemset/problem/461/B

大致思路:

树形DP!每个点维护两个值,一个值dp[root][0]是这个点不和黑相连,其余子树保证唯一黑点的切割情况,另一个值dp[root][1]是这个点开始的子树的切割情况。刚开始时,黑点是0和1,然后白点是1和0;状态转移的时候,碰到child开始的子树没有黑点的child,直接跳过,有黑点情况的,          

dp[root][1]=dp[root][0]*dp[child][1]%mod+dp[root][1]*(dp[child][0]+dp[child][1])%mod;

dp[root][0]=dp[root][0]*(dp[child][0]+dp[child][1])%mod;

参考代码:

http://codeforces.com/contest/461/submission/7985886


459E Pashmak and Graph

题目描述:http://codeforces.com/problemset/problem/459/E

大致思路:

神奇的在有向图上的DP,不过无后效性很明确,因为只有小边能够更新大边,开始先根据边权排序,也可以用vector,边权较小。然后我的方法是每个点维护三个值,pr,v1,v2,pr代表这个点最新接进来的权值,v1代表pr权值接进来的以这个点为终点的最长不下降道路序列长度,v2代表小于这个权值接进来的最长不下降道路序列长度。为什么这么做原因很简单,因为同样边权是不能更新同边权的。若新边权值大于pr,则v1,v2结合,若一样,就通过v2来更新。

参考代码:

http://codeforces.com/contest/459/submission/8046541


476E Dreamoon and Strings

题目描述:http://codeforces.com/problemset/problem/476/E

大致思路:DP一般先贪心,形成一个P,我们一定是通过减少最少的步数使其形成,所以先预处理出S中每一个字符,若这个字符等于P最后一个字符,就记录下能和它形成P的最近的一个P的第一个字符,若无法形成或者非P的最后一个字符,就记为-1,几个例子:

axbaxxbab 预处理的结果为-1 -1 0 -1 -1 -1 3 -1 7

然后DP[i][j]为前i个取j个的最大个数,对于每个DP[i][j]都有     dp[j][i]=max(dp[j][i],max(dp[j-1][i],dp[j-1][i-1]));

然后若这个字符预处理的结果非-1,即它能通过减去特定字符多形成一组P,那么这个状态就可以通过dp[j][i]=max(dp[j][i],dp[pre[j-1]][t2]+1);这样推得,t2为除了形成这一段P需要减去的t1之外,共减去i个情况下还需要减去的个数。

代码:http://codeforces.com/contest/476/submission/8218684


479E Riding in a Lift

题目描述:http://codeforces.com/problemset/problem/479/E

大致思路:还算是简单的DP,但是比赛中我第二题搞了太长时间导致没时间搞这题,总的来说我还是太菜了。方法就是n^2,sum[i]为dp[1-i][j-1]的和,dp[i][j]=sum[i-1]+sum[fun1(i,b)]-sum[i],fun1函数是个简单的判断,即判断最远能够跳到i的楼层,这样做开始得处理下a,b,如果a>b,那a=n-a+1,b=n-b+1;

代码:http://codeforces.com/contest/479/submission/8326436


478D Red-Green Towers

题目描述:http://codeforces.com/problemset/problem/478/D

大致思路:略带暴力的一道DP,题目中明确说明对于r+g,求达到最高高度情况下的种数,200000*2是四十万,高度最高920,可以发现答案就是在可行前提下,不同数量的,红色砖块的可摆放的方案之和。即01背包,虽然理论复杂度有10^8,但是题目给了两秒,而且01背包也有优化可以使复杂度/2,不会超时的,算完背包就等于得到了h高度下,不同数量的,红色砖块的可摆放方案,把可行解找出来求和就可以了。mod那里细节要处理好,不然可能会被卡常数。

代码:http://codeforces.com/contest/478/submission/8327179


486D Valid Sets

题目描述:http://codeforces.com/problemset/problem/486/D

大致思路:这道DP题做出的关键在于找准切入点,而找准切入点的技巧是把段化点,每个符合条件的子串都拥有一个最小值,对应树上的每个节点值,所以这题的做法就是,枚举根节点,只计算节点值等于根节点值或者在根节点值+d范围以内的儿子节点有了这个大前提,就可以发现,其中i为根节点,j为符合条件的儿子节点。

代码:http://codeforces.com/contest/486/submission/8677006


489F Special Matrices

题目描述:http://codeforces.com/problemset/problem/489/F

大致思路:记忆化搜索,状态用列上1的个数和0的个数表示出来,最终结果一定是0个列上1和0个列上0,即全部为2.那么就可以逆推了,开始时,只有给出的状态,dp记为1,其余全部为-1,表示还未计算过,对于给定的on(列上1的个数)和ze(列上0的个数),有三种方法推到它,一个是之前情况on中选两个,由dp[on+2][ze]推得,一个是之前情况on中选一个,ze中选一个,由dp[on][ze+1]推得,因为此时ze减少一个的同时,on也加了一个,on又得减少一个,故得此。第三种情况是之前情况ze中选两个,由dp[on][ze+2]推得,具体细节自己处理一下。

代码:http://codeforces.com/contest/489/submission/8794502


487B Strip

题目描述:http://codeforces.com/problemset/problem/487/B

大致思路:数据结构+二分查找+DP思想,做出这题得靠DP的思想,设f[i]为1---i这一段的最小划分,f[j]可以由1---(j-1)这一段上的f[i]转移过来,只要判断i---j是否能构成新的一段即可,这可以用ST算法O(1)(构造需要nlog(n))的时间出来,判断一下最大值和最小值是否符合就可以。但是n*n的时间复杂度显然是不够看的,所以要用二分查找来加速,变成nlog(n),仔细思考后会发现,因为有l的限制,所以其实f[j]只能由1---(j-l-1)这一段中的f[i]转移过来,并且这一段中的f[i]是单调递增的,所以二分这一段就可以了。

代码:http://codeforces.com/contest/487/submission/8896866


508E Arthur and Brackets

题目描述:http://codeforces.com/problemset/problem/508/E

大致思路:DP一般先贪心,对于这道题,每个左括号要选择最靠近自己左范围的奇数距离,偶数距离是不可能的。为什么这样,你可以这样想,如果全是1显然满足,然后如果有一个左括号不得不选x,那就意味着它的前一个左括号就必须选择1或者大于x的距离了,x越大越不利。有了这个贪心的前提下,就是状态转移了,fa[i]表示该距离可行,每个左括号哪些距离可行仅由自己后面的左括号选择的距离所决定,并且注意如果i+1括号选择的距离为3,意味着i+2左括号被i+1左括号所利用,就不能通过它来更新i了。具体细节自己处理好。

代码:http://codeforces.com/contest/508/submission/9794923


510D Fox And Jumping

题目描述:http://codeforces.com/problemset/problem/510/D

大致思路:很巧妙的一道状压DP,要是以为是背包的话,你就走远了。

                  先贪心一下吧,想要每个点都能走到,那几个数字凑来凑去一定能得到1,这里有个定理,当且仅当几个数最大公约数为1的时候能凑出1.所以这题就变成了素因数的问题,10^9的范围,素因数最多有9个,设dp[i][j]为选了魔法i,状态为j时的最优值。状态j为选了自己能够得到的最大公约数,这只跟自己的素因数有关系,而且注意最大公约数为4这种的没有必要考虑,因为在计算除1之外的最大公约数时素因数才最重要,4相当于2。所以这个状态最多为2^9=512,即9个素因数选择了哪些。状态出来了,转移方程也就不难了,dp[i][j]=min(dp[i][j],dp[j][k]+c[i]);其中j=gcd(a[i],fun(k));fun(k)为j魔法k状态对应的最大公约数。最后比较所有魔法的0状态,即得到1的最大公约数的值。具体细节自己处理一下。

代码:http://codeforces.com/contest/510/submission/10021447


417D Cunning Gena

题目描述:http://codeforces.com/problemset/problem/417/D

大致思路:战术组合DP,m只有20,故可以状态压缩。但是状态有1000000个,100个人不可能轮番把所有状态都判一遍,所以要用vector把更新的状态保存下来,初始只有0.还有最关键一个问题,k的处理,其实也简单。不用多增加一围,只要把人根据k从小到大排序,这样当出现问题全部解决的时候的这个k是最大的,只要这个时候计算k*b就行了。细节自己处理一下。

代码:http://codeforces.com/contest/417/submission/10607589


580D Kefa and Dishes

题目描述:http://codeforces.com/problemset/problem/580/D

大致思路:2015.10.02日 这时我应该已经保研成功了,好久没有畅快淋漓地做这种状态压缩DP了。这道题,要注意对于一个序列来说,向前继续吃和向后继续吃是统一的。所以只要计算一直向前吃就好了,状态为dp[n][2^n]表示以n为开头,吃了哪些东西的状态。状态转移方程也很容易,即

dp[j][f4]=max(dp[j][f4],dp[i][f2]+f[j][i]+a[j]),f4表示吃了j之后的新状态,f2表示未吃j之前的状态,f[j][i]表示向前吃j。复杂度O((2^n)*n*n);

代码:http://codeforces.com/contest/580/submission/13339350



0 0
原创粉丝点击