HDU 6774 String Distance(最长公共子序列 LCS)
Posted jpphy0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6774 String Distance(最长公共子序列 LCS)相关的知识,希望对你有一定的参考价值。
问题
HDU 6774 String Distance - https://acm.hdu.edu.cn/showproblem.php?pid=6774
分析
- 贪心不成立
- 若区间 [ l , r ] [l,r] [l,r]与B串的最长公共子序列为 l c s lcs lcs,则 a n s = r − l + 1 + l e n B − 2 ∗ l c s ans = r -l+1+lenB-2*lcs ans=r−l+1+lenB−2∗lcs
- 因此本题的实质是求 A 的子串与 B 的最长公共子序列
算法
引导
- 问1:设串 A A A 以 l l l 为起点,到 r 1 r_1 r1 位置与 B B B 串的最长公共子序列的长度为1
- 问2:设串 A A A 以 l l l 为起点,到 r 2 r_2 r2 位置与 B B B 串的最长公共子序列的长度为2
- ……
- 明显, r 1 < r 2 < r 3 < r 4 < ⋯ r_1 <r_2 <r_3 <r_4 < \\cdots r1<r2<r3<r4<⋯,
- 若 r i ≤ r < r i + 1 r_i \\leq r <r_{i+1} ri≤r<ri+1,表明:在给定的区间 [ l , r ] [l,r] [l,r] 内,能够形成的最长公共子序列的长度是 i i i,因此 l c s = i lcs =i lcs=i
- 当然,以上关系也可以表述为:若 r i ≤ r r_i \\leq r ri≤r,则 l c s = m a x ( l c s , i ) lcs =max(lcs,i) lcs=max(lcs,i)
如何计算
- 方法:动态规划(DP)
- 设 d p [ k , l e n ] dp[k,len] dp[k,len] 是 B B B 串的前 k k k 个字符与 A A A 的子串有长度为 l e n len len 的最长公共子序列时的最小右边界
- 若 d p [ k , l e n ] ≤ r dp[k,len] \\leq r dp[k,len]≤r,则此解为区间 [ l , r ] [l,r] [l,r] 与 B B B 串的前 k k k 个字符有长度为 l e n len len的最长公共子序列
- 辅助数组:设 n x t [ i , j ] nxt[i,j] nxt[i,j] 是 A A A 串的第 i i i 个字符处,下一个 j + ′ a ′ j+'a' j+′a′ 字符的位置(包括第 i i i 个字符),例如, A [ i ] = ′ b ′ A[i]='b' A[i]=′b′,则 n x t [ i ] [ ′ b ′ − ′ a ′ ] = i nxt[i]['b'-'a']=i nxt[i][′b′−′a′]=i;预处理此数组,复杂度 O ( 26 ⋅ L A ) O(26 \\cdot L_A) O(26⋅LA)
- 递推方程: d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j ] , d p [ n x t [ i − 1 ] [ j − 1 ] + 1 ] [ B [ i ] − ′ a ′ ] ) dp[i][j] = min(dp[i-1][j], dp[nxt[i-1][j-1]+1][B[i]-'a']) dp[i][j]=min(dp[i−1][j],dp[nxt[i−1][j−1]+1][B[i]−′a′])
- 每次查询进行一次递推计算,每次递推计算复杂度 O ( L B 2 ) O(L_B^2) O(LB2)
- q q q次查询的复杂度为: O ( 26 ⋅ L A + q ⋅ L B 2 ) O(26 \\cdot L_A+q\\cdot L_B^2) O(26⋅LA+q⋅LB2)
代码
#include<bits/stdc++.h>
using namespace std;
const int MXN = 100000+10;
char A[MXN], B[25];
int q, nxt[MXN][26], dp[25][25];
int solve(int l, int r){
int lcs = 0, lb = strlen(B+1);
memset(dp, 0x3f, sizeof dp);
for(int i = 1; i <= lb; ++i){
dp[i][1] = min(dp[i-1][1], nxt[l][B[i]-'a']);
if(dp[i][1] <= r && lcs < 1) lcs = 1;
}
for(int i = 2; i <= lb; ++i){
for(int j = i; j <= lb; ++j){
dp[j][i] = min(dp[j-1][i], nxt[dp[j-1][i-1]+1][B[j]-'a']);
if(dp[j][i] <= r && lcs < i) lcs = i;
}
}
return lcs;
}
int main(){
int t, l, r, lcs;
scanf("%d", &t);
while(t--){
scanf("%s%s%d", A+1, B+1, &q);
int len = strlen(A+1);
for(int i = 0; i < 52; ++i) nxt[len+1][i] = len+1;
for(int i = len; i > 0; --i){
for(int j = 0; j < 26; ++j) nxt[i][j] = nxt[i+1][j];
nxt[i][A[i]-'a'] = i;
}
len = strlen(B+1);
while(q--){
scanf("%d%d", &l, &r);
lcs = solve(l, r);
printf("%d\\n", r - l + 1 + len - (lcs<<1));
}
}
return 0;
}
以上是关于HDU 6774 String Distance(最长公共子序列 LCS)的主要内容,如果未能解决你的问题,请参考以下文章