HDU多校2 - 6774 String Distance(序列自动机优化lcs)

题目链接:点击查看

题目大意:给出两个字符串 A 和 B,规定两个字符串的距离 dis( s , t ) 为,可以在字符串 s 或 t 的任意位置添加或删除字符,使得两个字符串相等的最小操作次数,现在给出 q 次询问,每次询问给出字符串 A 的一个子串,问 dis( A[ l : r ] , B ) 是多少

题目分析:首先简化题目中的 dis 函数,假设 | s | < | t | ,再设 lcs 为其最长公共子序列的长度,我们可以将字符串 s 和 t 都变为 lcs,这样显然就相等了,将其转换为 lcs 只需要将多余的字母删除即可,操作数为 | s | - | t | - 2 * lcs

这样一来,对于每次询问,只需要求出 A 的子串与 B 串的 lcs 就好了,但是 A 的长度能达到 1e5 ,普通的 n * m 的求解方法肯定是不行的了,但是又考虑 B 的长度只有 20 ,所以可以考虑序列自动机优化,将求解 lcs 的时间复杂度下降到 m * m

具体优化方式如下,首先对 A 串建立序列自动机,nt[ i ][ j ] 表示从第 i 个位置往后(包含),首次出现字母 j 的位置,然后对于 B 串dp[ i ][ j ] 代表到第 i 位为止,lcs 为 j 时在 A 串最早结束的位置,这样 dp[ i ][ j ] 的转移无非只能从 dp[ i - 1 ][ j ] 和 dp[ i - 1 ][ j - 1 ] 的位置后找到首次出现 b[ i ] 的位置,取个最小值就好了,因为 dp 数组是可以迭代更新的,所以可以省去第一维

代码:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
 
typedef long long LL;
 
typedef unsigned long long ull;
 
const int inf=0x3f3f3f3f;

const int N=1e5+100;

char a[N],b[N];

int nt[N][26],dp[25];//dp[i][j]:到第i位为止,lcs为j时的最早结束位置 

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
    int w;
    cin>>w;
    while(w--)
    {
        scanf("%s%s",a+1,b+1);
        int n=strlen(a+1),m=strlen(b+1);
        for(int i=0;i<26;i++)
            nt[n+1][i]=n+1;
        for(int i=n;i>=0;i--)
        {
            for(int j=0;j<26;j++)
                nt[i][j]=nt[i+1][j];
            if(i>0)
                nt[i][a[i]-'a']=i;
        }
        int q;
        scanf("%d",&q);
        while(q--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            int lcs=0;
            memset(dp,0x3f,sizeof(dp));
            dp[0]=l-1;
            for(int i=1;i<=m;i++)
                for(int j=m;j>=1;j--)
                {
                    if(dp[j-1]<=r&&nt[dp[j-1]+1][b[i]-'a']<=r)
                        dp[j]=min(dp[j],nt[dp[j-1]+1][b[i]-'a']);
                    if(dp[j]<=r)
                        lcs=max(lcs,j);
                }
            printf("%d\n",r-l+1+m-2*lcs);
        }
    }














    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/107572993
今日推荐