1. 程式人生 > 實用技巧 >2020杭電多校第二場 1012.String Distance

2020杭電多校第二場 1012.String Distance

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=6774

題意:給你兩個字串A,B,|A|105,|B|20|A|≤105,|B|≤20,每次詢問A串的一個子串A[L]...A[R],問該子串通過插入和刪除一個字元的操作變得 和B字串相等的最少運算元

思路:設A子串為A,很容易可以發現最小運算元=|A|+|B|-2LCS(A,B)。因為插入操作其實是沒有意義的,對於最小運算元來說。

這個問題就轉換成了求子串和一個串的LCS。

如何求呢?

我們可以用一個nex陣列,nex[i][j]表示在第i個字元後出現j字元的位置。這樣就可以方便dp了。

定義 dp [ i ][ j ] , 其含義為 —— 和B的前 i 個字元 , 匹配了長度為j 的 LCS 的最短 A 字首。

那麼有dp[i][j]=min{dp[i][j],dp[i1][j]}

dp[i][j]=min{dp[i][j],Next[dp[i1][j1]][B[i]]}

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
int nex[100010][26],dp[21][26];
char str[100010
],pat[30]; int main() { int t; scanf("%d",&t); while(t--) { int N,M; scanf("%s",str+1); scanf("%s",pat+1); N=strlen(str+1); M=strlen(pat+1); memset(nex,0x3f,sizeof(nex)); for(int i=N;i>=1;i--) { for(int
j=0;j<26;j++) nex[i-1][j]=nex[i][j]; nex[i-1][str[i]-'a']=i; } int q; scanf("%d",&q); while(q--) { int L,R; scanf("%d%d",&L,&R); int ans=0; memset(dp,0x3f,sizeof(dp)); dp[0][0]=L-1; for(int i=1;i<=M;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],nex[dp[i-1][j-1]][pat[i]-'a']); } } int flag=0; for(int i=M;i>=0;i--) { for(int j=i;j<=M;j++) if(dp[j][i]<=R) { ans=i; flag=1; break; } if(flag==1) { break; } } //printf("ans:%d\n",ans); printf("%d\n",R-L+1+M-ans*2); } } return 0; }