hdu(三)1012 String Distance(子序列自动机、dp)

1012 String Distance

HDU 6774
题意:给定两个串S,T。可以在两个串中任意选定位置进行字符的插入或者删除。ST间的距离就是使得两字符串相等的最小操作数。
思考:
我猜是$|A|+|B|-LCS(A,B)$,当时好像没做不知道为啥可能我是菜鸡?先来一发再写
哦我知道了,后面还有一个q次询问区间把婷婷吓傻了,先来一发

我晕了就是这个区间搞死我了无语我想起来为啥没做了我全想起来了

做法:
现在已知答案就是给定的区间 A [ L , R ] 的 长 度 + B 的 长 度 − L C S ( A L − R , B ) A[L,R]的长度+B的长度-LCS(A_{L-R},B) A[LR]+BLCS(ALR,B),要求答案最小化,就是LCS最大化。
q q q次询问直接上dp复杂度 q ∗ n ∗ m ( 2 e 6 ∗ 1 0 5 ) q*n*m(2e6*10^5) qnm2e6105,显然不行。
那就把dp的两维内容转变为时间复杂度比较合适的。观察发现字符串 B B B的长度异常小( 20 20 20),用 d p [ i ] [ j ] dp[i][j] dp[i][j]记录 B B B前个字符与 A L − R A_{L-R} ALR前缀的公共子序列长度为 j j j时, A A A的最短前缀长度。
这样的状态转换只需要进行一次字符串 A A A的预处理,用 n x t [ i ] [ j ] nxt[i][j] nxt[i][j]记录 A A A串中位置 i i i之后(不包括 i i i)的字母 j j j第一次出现的地方。
dp状态转移方程: d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j ] , n x t [ d p [ i − 1 ] [ j − 1 ] ] [ B [ i ] − ′ a ′ ] ) dp[i][j]=min(dp[i-1][j],nxt[dp[i-1][j-1]][B[i]-'a']) dp[i][j]=min(dp[i1][j],nxt[dp[i1][j1]][B[i]a])

代码:```cpp
char a[maxn], b[22];
int dp[22][26], lena, lenb, nxt[maxn][26];
int lcs(int L,int R) {
mem(dp, inf);
dp[0][0] = L - 1;
for (int i = 1; i <= lenb; i++) {
dp[i][0] = L - 1;
for (int j = 1; j <= i; j++) {
dp[i][j] = min(dp[i][j], dp[i - 1][j]);
if (dp[i - 1][j - 1] < R) {
dp[i][j] = min(dp[i][j], nxt[dp[i - 1][j - 1]][b[i] - ‘a’]);
}
}
}
//找最大的lcs返回
for (int i = lenb; i >= 0; i–) {
for (int j = i; j <= lenb; j++) {
if (dp[j][i] <= R)return i;
}
}
return 0;
}
void init() {
mem(nxt, inf);
for (int i = lena; i > 0; i–) {
for (int j = 0; j < 26; j++) {
nxt[i - 1][j] = nxt[i][j];
}
nxt[i - 1][a[i] - ‘a’] = i;
}
}
int main() {
int T;
int q, l, r;
sci(T);
while (T–)
{
scanf("%s", a + 1);
scanf("%s", b + 1);
lena = strlen(a + 1);
lenb = strlen(b + 1);
init();
sci(q);
while (q–)
{
sci(l); sci®;
printf("%d\n", r - l + 1 + lenb - lcs(l, r) * 2);
}
}
return 0;
}


猜你喜欢

转载自blog.csdn.net/weixin_44986601/article/details/108782754
今日推荐