2020杭电多校第二场 L - String Distance - dp

Description

给定两个字符串 \(S,T\),每个询问会指定 \(S\) 的一个子串和 \(T\) 作为两个操作串 \(A,B\),每次可以选择任意一个字符串插入/删除一个字母,回答使得两个操作串相同的最小代价。\(|S| \le 10^5, |T| \le 20\)

Solution

插入操作是没用的,于是两个串的距离为 \(|A|+|B|-2LCS(A,B)\)

预处理 \(g[i][j]\) 表示 \(A[i..n]\) 中字符 \(j\) 最早出现的下标

对于每个询问,暴力 DP

\(f[i][j]\) 表示与 \(B[1..i]\) 的公共序列长度达到 \(j\)\(A[l..r]\) 的最短前缀的长度

\[g[f[i][j]+1][B[i+1]] \to f[i+1][j+1] \\ f[i][j] \to f[i+1][j] \]

\[f[i][j]=\min(f[i-1][j], g[f[i-1][j-1]][B[i]]) \]

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;

int n,m,q,s[N],t[N],f[25][25],g[N][30];

void make_g()
{
    for(int c=0;c<26;c++)
    {
        int i=1,j=1;
        while(i<=n)
        {
            while(s[i]!=c && i<=n) ++i;
            if(s[i]==c) for(;j<=i;j++) g[j][c]=i;
            ++i;
        }
        while(j<=n) for(;j<=n;j++) g[j][c]=n+1;
    }
    for(int c=0;c<26;c++) g[0][c]=g[1][c], g[n+1][c]=g[n+2][c]=n+1;
}

void solve()
{
    memset(f,0,sizeof f);
    memset(g,0,sizeof g);
    string ss,tt;
    cin>>ss>>tt;
    n=ss.length();
    m=tt.length();
    memset(s,0,sizeof s);
    memset(t,0,sizeof t);
    for(int i=1;i<=n;i++) s[i]=ss[i-1]-'a';
    for(int i=1;i<=m;i++) t[i]=tt[i-1]-'a';
    make_g();

    cin>>q;
    while(q--)
    {
        int l,r;
        cin>>l>>r;
        for(int i=0;i<=m;i++)
        {
            for(int j=0;j<=m;j++)
            {
                f[i][j]=n+1;
            }
        }
        f[0][0]=l-1;
        for(int i=1;i<=m;i++)
        {
            f[i][0]=f[i-1][0];
            for(int j=1;j<=i;j++)
            {
                f[i][j]=min(f[i-1][j],g[f[i-1][j-1]+1][t[i]]);
            }
        }
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            if(f[m][i]<=r) ans=i;
        }
        cout<<r-l+1+m-2*ans<<endl;
    }
}

signed main()
{
    ios::sync_with_stdio(false);

    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }
}
/*
1
qaqaqwqaqaq
qaqwqaq
3
1 7
2 8
3 9
*/

猜你喜欢

转载自www.cnblogs.com/mollnn/p/13375491.html