2021-04-17

线性dp总结
还是由最长公共子序列来就此展开,给定两个长度分别为n,m的字符串a,b,求既是a的子序列,又是b的子序列的字符串的长度最长是多少。首先为状态表示,就是说先对于两个序列来说,两者互相独立,互不干扰,要使用二维dp来存储信息。dp[i,j]表示a[1i]与b[1j]的最长公共子序列的长度,然后再进行阶段划分,已经处理的前缀长度(两个字符串中的位置,即一个二维坐标),通过长度来扩散至整个区间。最后写转移方程,转移方程:若a[i]==b[j]:dp[i,j]=dp[i-1][j-1]+1; 否则,dp[i][j]=max(dp[i+1][j],dp[i][j-1]);边界:dp[i][0]=0;dp[0][j]=0;例如如下题,给出3n个数要求去掉n个数使得剩下的前n个数-后n个数的差最大。显然是一道如果数据小直接dpf[i][j]表示前i个取j个最大是多少,dpe[i][j]后i个取j个最小是多少。转移也是很明显的dpf[i][j]=max(dpf[i][j],dpf[i-1][j-1]+a[i]),dpe[i][j]=min(dpe[i][j],dpe[i+1][j-1]+a[i]);dpf[i]表示前i个取n个最大是多少,dpe[i]表示后i个取n个最小是多少。要做好线性DP一个是阶段点的选取,或者说是基准的选取,这一步是所有dp问题的关键,只有找到合适的阶段,问题才有解决的可能。找出阶段点所表示的含义,他具体代表什么,是代表他之前的阶段的最优值还是他之后的最优值,还是某种状态下的最优值,有时找到的是每种状态下的最优值,最后还要在dp【n】【i】(i属于1到n)中选择最优。找出这个阶段点有几种状态,给每种状态找到一种表示,找出这种状态与之前的状态的关系,这时状态转移方程或者说转移关系就基本上明确了。如题,给定m种不同字母,要求从m种字母中选出并组成合法名字,当
任意字母不同时出现在姓和名中时称这个名字是合法的,姓和名的长度
均为n,问最多可以组成多少个合法的名字。
其实呢这个问题就相当于涂色,给定m种颜色,为两个长度为n的单元格涂色,要
求两个区域没有共同的颜色。这个题的方法就是先考虑姓,得到长度为
n的分别用了j=1到m种颜色的方案数,那么对于名,就是(m-j)^n,即剩
下的颜色填到n个格子的方案数。
dp[i][j]表示长度为i,用到j种颜色的情况数,显然dp[1][1]=m,状态转移
方程为:
dp[i][j]=dp[i-1][j]j+dp[i-1][j-1](m-(j-1))。
长度为i用到j种颜色的数目=长度为i-1用到j种颜色的数目
j种颜色(第i
个格是j种颜色中的一种)+长度为i-1用到j-1种颜色*(m-(j-1))种颜色
(第i个格用的是剩下的m-(j-1)种颜色)。由此#include<stdio.h>
typedef long long ll;
const ll mod=1e9+7;
ll pow(ll x,ll n)
{
ll res=1;
while(n>0)
{
if(n&1) res=resx%mod;
x=x
x%mod;
n>>=1;
}
return res;
}
ll dp[2005][2005]; //表示当长度为i时使用j种颜色的情况数目,这种处理方法确实很巧妙。经典dp有的题确实很难,很难理解,慢慢刷题吧,一天差不多1到2个题,对于贪心那次作业,自己确实实实在在有在思考题,也有了自己的学习方法,虽然有时候就是做不出来,但我心里就是喜欢那种思考题,然后ac的感觉。所以还是要通过刷题来提高自己的水平,以后一定会更好一点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值