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] [lr]与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=rl+1+lenB2lcs
  • 因此本题的实质是求 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} rir<ri+1,表明:在给定的区间 [ l , r ] [l,r] [lr] 内,能够形成的最长公共子序列的长度是 i i i,因此 l c s = i lcs =i lcs=i
  • 当然,以上关系也可以表述为:若 r i ≤ r r_i \\leq r rir,则 l c s = m a x ( l c s , i ) lcs =max(lcs,i) lcs=max(lcsi)

如何计算

  • 方法:动态规划(DP)
  • d p [ k , l e n ] dp[k,len] dp[klen] 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[klen]r,则此解为区间 [ l , r ] [l,r] [lr] B B B 串的前 k k k 个字符有长度为 l e n len len的最长公共子序列
  • 辅助数组:设 n x t [ i , j ] nxt[i,j] nxt[ij] 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][ba]=i;预处理此数组,复杂度 O ( 26 ⋅ L A ) O(26 \\cdot L_A) O(26LA)
  • 递推方程: 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[i1][j],dp[nxt[i1][j1]+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(26LA+qLB2)

代码

#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)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 6774 String Distance 序列自动机优化lcs

hdu 2736 Average distance

hdu 4712 Hamming Distance 随机

hdu 5903 Square Distance(dp)

HDU-2376Average distance

HDU 5903 Square Distance