DP题组部分题解

129 阅读3分钟

题目链接:

vjudge.net/contest/422…

1.24做过部分,2.15重做

A-Max Sum Plus Plus

基于基础DP。

要求包含n个数的数组a的m个最大子段和。

令dp[i][j]表示以a[j]结尾的i个最大子段和。

那么状态转移方程dp[i][j]=max(dp[i-1][k]+a[j],dp[i][j-1]+a[j]);(i-1≤k≤j-1)

由于只用到了上一层的最大值,因此可以转换为一维滚动数组。

第i次循环表示分为i段。

用mx[j]记录上一层到以j-1结尾为止的最大值,dp[j]表示以第j个数为结尾的最大值

转移方程可写为:dp[j]=max(mx[j-1],dp[j-1])+a[j];

每次计算完成后,更新mx和tmp的值:mx[j-1]=tmp,tmp=max(tmp,dp[j])。

B-Ignatius and the Princess IV

基于自组织线性表,根据访问频率排序。

根据题意,只需要维护一个空间为2的表即可。访问结束时表首元素即为输出元素。

C-Monkey and Banana

第一次是用DAG写的,采用记忆化搜索递归,结果TLE了。

第二次用基础DP。

每个木块长宽高互换共6种,存到结构体block中,按照先长度降序,再宽度降序排序。

数组dp[i]表示第i个木块在最上面能达到的最大高度。初始化为0。

转移方程:dp[i]=max(dp[j])+block[i].height,其中b[j].length>b[i].length&&b[j].width>b[i].width。

最后找到dp数组的最大值输出即可。

D-Doing Homework

基于状压DP,暂时不会做

E-Super Jumping! Jumping! Jumping!

基于基础DP算法

数组a标记各个位置的分值。数组dp标记跳到i位置的最大分值。

数组的0位置为起点

DP转移方程:dp[i]=max(dp[j]+a[i]),其中0<=j<i且a[j]<a[i]。

结果为dp[n]。

F-Piggy-Bank

基于基础DP算法。

数组sum[i]表示重量为i时的最小金额,初始化为0。

转移方程:sum[i]=min(sum[i-w[j]]+p[j])。其中w[j],p[j]为第j个硬币的重量和面值。

结果为sum[F-E],DP是注意边界条件即可。

G-天上掉馅饼

基于BFS,某一刻,某位置的最大馅饼数量为前一刻该位置或与其相邻的位置上的最大馅饼数量加上该位置该时刻掉落的馅饼数量。

当然,初始化时将除了位置5以外的所有位置初始化为负无穷,位置5初始化为0,最后求11个位置上馅饼数最大值即可。

H-Tickets

基于基础DP。

dp[i]表示到第i个人为止的最短买票时间,S[i],D[i]分别表示第i个人单独买票的时间和第i、i+1个人一起买票的时间。

状态转移方程:dp[i]=min(dp[i-1]+S[i],dp[i-2]+D[i-1]);

结果为dp[K]。

I-导弹拦截2

不断遍历,求升序序列并把每次已经拦截的导弹删除或者标记,直到所有导弹都被拦截即可。

升序序列不需要取最长的,只要当前导弹能被拦截就拦截并更新高度。

J

该问题不仅要求按照老鼠重量和速度分别严格升序和降序的最大长度,还要求是哪几只老鼠。

定义老鼠的结构体mouse,有三个值:w,v,num,分别是重量,速度和编号。

用DAG模型,进行DP即可。

因为输出需要重量从小到大,先将老鼠按照重量降序,速度升序的顺序排列。

转移方程:dp[i]=max(dp[i],dp[j]+1),其中m[i].w<m[j].w&&m[i].v>m[j].v,并且每次更新值时将其前驱的值记录下来用以回溯.

找到dp值最大的一只老鼠,不断回溯输出即可。

K

不会。。

L

最长公共子序列问题。采用dp的方法。两个字符串str1,str2,dp[i][j]表示str1中前i个字符和str2中前j个字符的最长公共子串。

若str1[i]==str2[j],那么dp[i][j]=dp[i-1][j-1]+1;

否则,dp[i][j]=max(dp[i-1][j],dp[i][j-1])。

结果为dp[str1.length()-1][str2.length()-1]。

M

注意到从高为h处掉落,那么掉落花费的时间都是一样的,即为h,只需要比较跑动的时间即可。

N

最长升序子列问题。

设数组为a,dp[i]表示以a[i]结尾的最长升序子列。

那么,转移方程:dp[i]=max(1,dp[j]+1),其中j<i且a[j]<a[i]。

结果为dp数组的最大值。

O

根据题意,每次拿走左边或者右边的treat,要求最大值。

dp[i][j]表示第i天拿走treat之前剩下的是第j到第j+n-i个treat。

那么转移方程:dp[i][j]=max(dp[i+1][j]+i*v[j+n-i],dp[i+1][j+1]+i*v[j]);

结果为dp[1][1]。

P

根据题意,老鼠能每次水平或垂直移动最多k格的距离,并且每次移动都需要移动到奶酪更多的格子上。

每个点都有两个值:这个点储存的奶酪cur和到达这个点能吃到的最多的奶酪sum(不包括这个点)。

采用优先队列,从(0,0)开始,每次将老鼠可能到达的点送进队列中。

每次从队列中取出第一个点p[i][j],依次判断所有它可能到达的点,若某个点p[l][j].sum>p[i][j].sum+p[i][j].cur,则不需要继续搜索,因为已经有其他更优的路线能到达该点。

不断搜索直至队列为空。

取所有点中sum不为0(代表可以到达)且sum和cur的最大和输出。

若没有,说明只能吃原点的奶酪,输出原点的cur即可。

Q

题意要求最大对称子阵。

易知,如果最大对称子阵的阶数为k,那么一定会有k-1阶,k-2阶...,2阶对称子阵。

那么不断遍历并寻找2阶子阵,再在此基础上不断扩大,求该对称子阵的最大阶数。

注意有两个方向,全部遍历完后,取最大值即可。结果这个思路TLE了。

R

需要确定挤牛奶的最大值,且两次挤牛奶时间间隔不能小于R。先将挤牛奶的操作按照开始时间升序排序。

用DP[i]表示第i次挤牛奶之后的最大可能获得牛奶的数量(必须使用第i次)。

转移方程:DP[i]=max(DP[j])+efficiency[i];其中第j次挤牛奶的结束时间跟第i次挤牛奶的开始时间要相差超过R。

结果为DP[i]的最大值。