欢迎来到SamXia的博客|

SamXia

园龄:1个月粉丝:1关注:2

2025-01-26 14:13阅读: 9评论: 0推荐: 0

dp深入与进阶(1):线性dp+区间dp(2025.01.24)

01.线性dp(多维状态定义)

Luogu P1136 [迎接仪式]

根据题面考虑不交换j,z 而是对j,z“取反”

设置状态f(i,j,p,b)

i 个字符进行j次字符j的取反,

p次字符z的取反,

b010指当前位为j,1指当前位为z

f为该条件下的最大价值

初始状态:f(0,0,0,1)=0,利用性质:z+z/j不满足条件)

讨论:

01.对于f(i,j,p,0)

i.若该位置原本为z,通过修改后变为j:

f(i,j,p,0)=max(f(i1,j,p1,1),f(i1,j,p1,0))

ii.若该位置原本就为j:

f(i,j,p,0)=max(f(i1,j,p,0),f(i1,j,p,1))

02.对于f(i,j,p,1)

i.若原来位置为j,通过修改后变为z

f(i,j,p,1)=max(f(i1,j1,p,0)+1,f(i1,j1,p,1))

ii.若该位置原本就为z

f(i,j,p,1)=max(f(i1,j,p,0)+1,f(i1,j,p,1))

暴力O(nk2)dp即可

02.区间dp

i.Luogu P1063[能量项链]

原题求一条长度为n的环的合并最大价值

可以将两条长度为n的链相连,形成长为2n的链

如此便将环的问题转化为了链上的区间dp问题

考虑定义f(i,j)[i,j]区间合并产生的最大能量

对于f(i,j):

有区间dp方程f(i,j)=maxk[i,j](f(i,k)+f(k+1,j)+headi×tailk×tailj)

初始状态定义为f(i,i)=0,i[1,n]

最后用for循环枚举k,区间dp即可

核心代码:

for(int len=1;len<n;++len)//枚举区间[i,j]的长度
for(int i=1,j=i+len;i+len<=2*n;++i,++j)//枚举起始点i和区间结尾j
for(int k=i;k<j;++k)//枚举中转点
f[i][j]=max(f[i][k]+f[k+1][j]+head[i]*tail[k]*tail[j],f[i][j]);//区间dp:能合并就尝试合并
for(int i=1;i<=n;++i)
ans=max(ans,f[i][i+n-1]);

ii.Luogu P1005 [矩阵取数游戏]:

考虑定义f(i,l,r)表示对于 单行(第i行) 内剩下[l,r]区间时的最大得分和

考虑对于剩余区间[l,r]两种获得方法:

01.上一步取a[l1],有:

f(i,l,r)=f(i,l1,r)+a[i][l1]2m(rl+1)

02.上一步取a[r+1],有:

f(i,l,r)=f(i,l,r+1)+a[i][r+1]am(rl+1)

暴力枚举i,l,r,最后开高精度求取答案即可

核心代码:

for(int i=1;i<=n;++i)
for(int l=1;l<=m;++l)
for(int r=m;r>=l;--r)//枚举区间[l,r]
f[i][l][r]=max(f[i][l-1][r]+1ll*a[i][l-1]*(1<<(m-(r-l+1)))/*要么是在选走l-1后变为[l,r]的区间*/,f[i][l][r+1]+1ll*a[i][r+1]*(1<<(m-(r-l+1)))/*要么是在选走r+1后变为[l,r]的区间*/);
for(int i=1;i<=n;++i)
{
for(int l=1;l<=m;++l)
maxn=max(f[i][l][l]+(1ll<<m)*a[i][l],maxn);
ans+=maxn;
}

本文作者:SamXia

本文链接:https://www.cnblogs.com/SamXia/p/18691759

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   SamXia  阅读(9)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起