Description
Input
Output
有一个特殊的性质:
一段长度为 $k$ 的连续空格的代价为 $-A-B(k-1)$.
可以看成第一个空格的代价为 $-A$, 其它空格代价为 $-B$.
那么我们就设状态 $f[i][j],g[i][j],h[i][j]$ 分别表示 $S$ 串前 $i$ 个与 $T$ 串前 $j$ 个达到长度相同,且最后一个字符分别为 字母/字母,字母/空格,空格/字母的最大相似度.
因为不可能出现空格/空格的情况,所以就不设这个状态了.
考虑转移:
$f[i][j]$ :
- $\leftarrow f[i-1][j-1]+d(S[i],T[j])$.
$g[i][j]$:
- $\leftarrow g[i-1][j]-A$.
- $\leftarrow f[i-1][j]-B$.
- $\leftarrow h[i-1][j]-A$
$h[i][j]$:
- $\leftarrow g[i][j-1]-A$.
- $\leftarrow f[i][j-1]-A$.
- $\leftarrow h[i][j-1]-B$.
#include <cstdio> #include <cstring> #include <algorithm> #define N 3003 #define ll long long #define setIO(s) freopen(s".in", "r" , stdin) using namespace std; char str[N]; int S[N], T[N], d[6][6], n, m; ll f[N][N], g[N][N], h[N][N]; int id(char c) { if(c == 'A') return 1; if(c == 'T') return 2; if(c == 'G') return 3; if(c == 'C') return 4; } int main() { // setIO("input"); int i , j, A, B; scanf("%s", str + 1), n = strlen(str + 1); for(i = 1; i <= n ; ++ i) S[i] = id(str[i]); scanf("%s", str + 1), m = strlen(str + 1); for(i = 1; i <= m ; ++ i) T[i] = id(str[i]); for(i = 1; i <= 4 ; ++ i) { for(j = 1; j <= 4; ++j) scanf("%d", &d[i][j]); } scanf("%d%d", &A, &B); memset(f, -63, sizeof(f)), memset(g, -63, sizeof(g)), memset(h, -63, sizeof(h)); g[1][0] = h[0][1] = - A, f[0][0] = 0; for(i = 1; i <= n ; ++ i) { for(j = 1; j <= m ; ++ j) { f[i][j] = max(f[i - 1][j - 1], max(g[i - 1][j - 1], h[i - 1][j - 1])) + d[S[i]][T[j]]; g[i][j] = max(max(f[i - 1][j], h[i - 1][j]) - A, g[i - 1][j] - B); h[i][j] = max(max(f[i][j - 1], g[i][j - 1]) - A, h[i][j - 1] - B); } } printf("%lld\n", max(max(f[n][m], g[n][m]), h[n][m])); return 0; }