zoukankan      html  css  js  c++  java
  • 【2020杭电多校round2】HDU6774 String Distance

    题目大意

    题目链接

    对于两个串$s,t$。你可以进行若干次操作。一次操作,你可以:

    • 在$s$或$t$里的任意位置插入一个字符。
    • 或在$s$或$t$里的任意位置删除一个字符。

    我们定义两个串$s,t$的“距离”为,能使$s,t$相等的,最少操作次数。

    现在给定两个串$A[1dots n],B[1dots m]$,和$q$次询问。

    每次询问给定两个整数$l_i,r_i$ ($1leq l_ileq r_ileq n$),求$A[l_idots r_i]$和整个$B$的“距离”。

    $T$组数据。

    数据范围:$1leq Tleq 10$,$1leq n,qleq 10^5$,$1leq mleq 20$。

    本题题解

    首先,经过初步分析,两个串$s,t$的距离就等于$|s|+|t|-2cdot ext(s,t)(。其中) ext$表示最长公共序列。于是问题转化为,每次求$A[ldots r]$和$B$的最长公共子序列。

    注意到$B$很小而$A$很大,所以要努力使一次询问的复杂度,与$A$的长度(也就是和$r-l+1$)无关。

    可以做一些预处理。设$dp[i][j][k]$,表示$A[idots n]$和$B[jdots m]$这两个串,所有长度为$k$的公共子序列里,在$A$上结尾最小是多少。换句话说,$dp[i][j][k]$就是最小的$pgeq i$,满足$A[idots p]$和$B[jdots m]$有长度为$k$的公共子序列。如果不存在这样的$p$,则令$dp[i][j][k]=n+1$。

    这个预处理挺有技巧的,不是简单枚举,而需要DP:用已知的来推未知的。我们倒着枚举所有$i$。每个$dp[i][j][k]$,都从$dp[i+1][dots][dots]$转移过来。转移时,有两种情况:$i$在不在这个公共子序列里,分别考虑一下,两种情况取个$min$即可。

    预处理完$dp$数组后。考虑回答询问。对一次询问,$A$的开始位置是$l$我们已经知道了。可以暴力枚举$B$的开始位置$j$,再暴力枚举公共子序列长度$k$,看$dp[l][j][k]$是否小于等于$r$。如果小于等于$r$,用$k$更新$ ext$的长度即可。

    时间复杂度$O((n+q)m^2)$。

    参考代码(ps. 本题需要使用fread,可以去这里粘个板子):

    #include <bits/stdc++.h>
    using namespace std;
    
    #define pb push_back
    #define mk make_pair
    #define lob lower_bound
    #define upb upper_bound
    #define fi first
    #define se second
    #define SZ(x) ((int)(x).size())
    
    typedef unsigned int uint;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    
    template<typename T>inline void ckmax(T& x,T y){x=(y>x?y:x);}
    template<typename T>inline void ckmin(T& x,T y){x=(y<x?y:x);}
    
    const int MAXN=1e5,MAXM=20;
    const int INF=1e9;
    int n,m,nxt_b[MAXN+5][26];
    int f[MAXN+5][MAXM+5][MAXM+5];
    char a[MAXN+5],b[MAXM+5];
    void get_nxt(char* s,int len,int nxt[MAXN+5][26]){
    	static int pos[26];
    	for(int i=0;i<26;++i)
    		pos[i]=len+1;
    	for(int i=len+1;i>=0;--i){
    		for(int j=0;j<26;++j)
    			nxt[i][j]=pos[j];
    		if(i!=0&&i!=len+1)
    			pos[s[i]-'a']=i;
    	}
    }
    void solve_case(){
    	cin>>(a+1); n=strlen(a+1);
    	cin>>(b+1); m=strlen(b+1);
    	get_nxt(b,m,nxt_b);
    	for(int j=1;j<=m;++j){
    		for(int k=1;k<=m;++k){
    			f[n+1][j][k]=n+1;
    		}
    	}
    	for(int i=n;i>=1;--i){
    		for(int j=1;j<=m;++j){
    			f[i][j][1]=f[i+1][j][1];
    			if(nxt_b[j-1][a[i]-'a']<=m){
    				f[i][j][1]=i;
    			}
    			for(int k=2;k<=m;++k){
    				f[i][j][k]=f[i+1][j][k];
    				if(nxt_b[j-1][a[i]-'a']<m)
    					ckmin(f[i][j][k],f[i+1][nxt_b[j-1][a[i]-'a']+1][k-1]);
    			}
    		}
    	}
    //	while(1){
    //		int i,j,k;
    //		cin>>i>>j>>k;
    //		cout<<f[i][j][k]<<endl;
    //	}
    	int q;cin>>q;while(q--){
    		int l,r;cin>>l>>r;
    		int ans=0;
    		for(int j=1;j<=m;++j){
    			for(int k=1;k<=m-j+1;++k){
    				if(f[l][j][k] > r)
    					break;
    				ckmax(ans,k);
    			}
    		}
    		ans=r-l+1+m-2*ans;
    		cout<<ans<<endl;
    	}
    }
    int main() {
    	int T;cin>>T;while(T--){
    		solve_case();
    	}
    	return 0;
    }
    
  • 相关阅读:
    Mac下eclipse安装SVN插件
    python中函数参数*args和**kw的区别
    Linux下安装JDK1.8
    SpringBoot Profiles特性
    一张图讲解单机FastDFS图片服务器安装步骤(修订版)
    一张图讲解最少机器搭建FastDFS高可用分布式集群安装说明
    Zookeeper作为配置中心使用说明
    一张图秒懂微服务网络架构
    TestNG的静态方法mock的步骤
    Java中indexOf的用法
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/13376648.html
Copyright © 2011-2022 走看看