题解 洛谷P4059 线性dp
前言
可怜的 zsw 被暴捶力,只能开始恶补 dp 了。
比较抽象,只是给自己看的。
思路
题意自己看啊啊啊。
为了方便表述,称第一个串为
看完后可以得知重要的一点:由于
所以同一行不可能出现两个空格,显然去掉它俩以后值更大。
那么有个初步思路,
然而你会发现根本做不了,因为相似度与每个元素的相对位置息息相关,但状态中根本没有涉及到相对位置,因此是个假做法。
for example,假设
考虑将
可是若
那么拓展状态是:
如上图所示,不同种类状态的拓展状态可能是不同的,只有二维的状态定义所带来的后果是毁灭性的。
不过这也带来启发,二维不行,加上一位就好了嘛。
对于所有空格,我们只关心末尾是否有空格,这不仅与
来看看它是怎么解决上述问题的:前者被分类为
再解释下“与
到此已经完成了
转移方程:
-
-
是第一个,形如: $×××i ××j* 发现了吗?考虑了空格后的状态,就能清晰表示出一列一列的不同情况。
有:
f_{i,j,1}=f_{i-1,j,0/2}-a 不是第一个:
×××i ×j** 显然,
i 的前一个字符必定非空格,于是f_{i-1,j,1} 形如这样:××(i-1) ×j* (这是为了说明不会漏情况)
那么直接转移就好,有:
f_{i,j,1}=f_{i-1,j,1}-b 总结下:
f_{i,j,1}=max(f_{i-1,j,0/2}-a,f_{i-1,j,1}-b) -
代码
注意初始化,思路清晰了就很容易一遍过的。
#include<bits/stdc++.h>
using namespace std;
#define s1(i) (s1[i]=='A'?1:(s1[i]=='T'?2:(s1[i]=='G'?3:4)))
#define s2(i) (s2[i]=='A'?1:(s2[i]=='T'?2:(s2[i]=='G'?3:4)))
string s1,s2;
int n,m,val[5][5],A,B,f[3005][3005][3];
signed main(){
cin>>s1>>s2;
n=s1.size(); m=s2.size();
s1=" "+s1; s2=" "+s2;
for(int i=1; i<=4;i++)
for(int j=1; j<=4;j++)
cin>>val[i][j];
cin>>A>>B;
memset(f,-0x3f,sizeof f);
for(int i=1; i<=n;i++) f[i][0][1]=-A-B*(i-1);
for(int i=1; i<=m;i++) f[0][i][2]=-A-B*(i-1);
f[0][0][0]=0;
for(int i=1; i<=n;i++){
for(int j=1; j<=m;j++){
f[i][j][0]=val[s1(i)][s2(j)]+max(f[i-1][j-1][0],max(f[i-1][j-1][1],f[i-1][j-1][2]));
f[i][j][1]=max(max(f[i-1][j][0],f[i-1][j][2])-A,f[i-1][j][1]-B);
f[i][j][2]=max(max(f[i][j-1][0],f[i][j-1][1])-A,f[i][j-1][2]-B);
}
}
cout<<max(f[n][m][0],max(f[n][m][1],f[n][m][2]));
return 0;
}