题解 洛谷P4059 线性dp
posted on 2023-09-18 08:37:07 | under 题集 | source
前言
可怜的 zsw 被暴捶力,只能开始恶补 dp 了。
比较抽象,只是给自己看的。
思路
题意自己看啊啊啊。
为了方便表述,称第一个串为 \(s1\),第二个为 \(s2\),字符串的下标从 \(1\) 开始。
看完后可以得知重要的一点:由于 \(A,B>0\),所以有 \(-A-B(k-1)\) 随 \(k\) 增大单调递减。
所以同一行不可能出现两个空格,显然去掉它俩以后值更大。
那么有个初步思路,\(f_{i,j}\) 表示 \(s1[1,i]\) 与 \(s2[1,j]\) 的最大相似度。
然而你会发现根本做不了,因为相似度与每个元素的相对位置息息相关,但状态中根本没有涉及到相对位置,因此是个假做法。
for example,假设 \(f_{1,2}\) 所代表的两串长这样:
\(A**\)
\(T*C\)
考虑将 \(i\) 拓展一位,那么该状态可以拓展至:
\(AT*\)
\(T*C\)
可是若 \(f_{1,2}\) 是这样子的:
\(**A\)
\(*TC\)
那么拓展状态是:
\(**AT\)
\(*TC*\)
如上图所示,不同种类状态的拓展状态可能是不同的,只有二维的状态定义所带来的后果是毁灭性的。
不过这也带来启发,二维不行,加上一位就好了嘛。
对于所有空格,我们只关心末尾是否有空格,这不仅与 \(A,B\) 有关,还和可转移到的状态有关,因此定义:
- \(f_{i,j,0}\):两串结尾均不是空格。
- \(f_{i,j,1}\):只有 \(i\) 所在串以空格结尾。
- \(f_{i,j,2}\):只有 \(j\) 所在串以空格结尾。
来看看它是怎么解决上述问题的:前者被分类为 \(f_{1,2,1}\),后者被分类为 \(f_{1,2,0}\),只需在状态转移时规定好即可。
再解释下“与 \(A,B\) 有关” 是什么意思:容易想到,\(g(k)\) 等价于首个空格减去 \(A\),此后连续的空格均是减去 \(B\),而我们的状态刚好可以解决这个问题,考虑上个状态末尾的空格即可。
到此已经完成了 \(50\%\) 了。
转移方程:
-
\(f_{i,j,0}=f_{i-1,j-1,0/1/2}+val(i,j)\),最简单的情况。
-
\(f_{i,j,1}\):可以分为两种,该空格是第一个和不是第一个。
是第一个,形如:
\(×××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)\)
-
\(f_{i,j,2}=max(f_{i,j-1,0/1}-a,f_{i,j-1,2}-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;
}

浙公网安备 33010602011771号