String Distance
题目大意
给两个字符串a,b。
a的长度是1e5,b的长度是20.
有两种操作:
选一个串在随便哪个位置插入随便哪个字符。
随便删除一个字符。
有q次询问,每次询问给出一个l,r 问a串的 l ~ r 区间与b字符串,经过多少次操作,能使他们相等?
废话:
做的时候好菜,想到了跟lcs有关,感觉是最长的那个串减去lcs 再乘2。错的,啊啊啊啊啊好菜啊,也不会快速求这个lcs
题解
添加几个字符,不如删除。
所有的添加操作都可以被删除操作替代。
这个,,我没想到
然后 答案就是r - l + m - 2 * lcs长度 m代表b串长度。
这个很好想。
然后 怎么快速的找最长公共子序列?
题解告诉我,先预处理一下nex[i][j] 代表a串第i个位置以后j字符出现的第一个位置。。然后用dp求最长公共子序列的长度。复杂度是m*m
然后 总的复杂度就是n * 26 + m * m * q
怎么用dp求?
dp[i][j] 表示1~i中可以组成的最长公共子序列长度为j的最长长度。
转移方程就是
dp[i][j] = min(dp[i][j],nex[dp[i - 1][j - 1] + 1][b[i] - 'a']);
记得初始化!!!!!!!!!!!!!!
。。 真心想不出来,脑子是个好东西。。
代码
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <unordered_map>
#include <cmath>
#include <set>
#include <cstring>
#include <string>
#include <unordered_set>
#include <bitset>
#include <stdlib.h>
#include <time.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef unsigned long long ull;
typedef set<int>::iterator sit;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void wenjian(){
freopen("concatenation.in","r",stdin);freopen("concatenation.out","w",stdout);}
void tempwj(){
freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){
return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){
a %= mod;ll ans = 1;while(b){
if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp2{
bool operator()(const pii & a, const pii & b){
return a.second < b.second;}};
int lb(int x){
return x & -x;}
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+5;
int nex[maxn][30]; // nex[i][j] 表示 i~n里 第一个字符j出现的位置的下标
int dp[30][30];
char a[maxn];
char b[31];
int main()
{
int T;
scanf("%d",&T);
while(T -- )
{
scanf("%s%s",a + 1,b + 1);
int n = strlen(a + 1);
int m = strlen(b + 1);
for (int i = 1; i <= n + 3; i ++ )
{
for (int j = 0; j < 26; j ++ )
{
nex[i][j] = n + 1;
}
}
for(int i = n; i >= 1; i -- )
{
for(int j = 0; j < 26; j ++ )
{
nex[i][j] = nex[i + 1][j];
}
nex[i][a[i] - 'a'] = i;
}
// for (int i= 1; i <= n; i ++ )
// {
// for (int j = 0; j < 26; j ++ )
// printf("%d ",nex[i][j]);
// printf("\n");
// }
int q;
scanf("%d",&q);
while(q -- )
{
int l,r;
scanf("%d%d",&l,&r);
for (int j = 0; j <= m; j ++ )
{
for(int k = 0; k <= m; k ++ )
dp[j][k] = inf;
}
dp[0][0]= l - 1;
int ans =0 ;
for (int i = 1; i <= m; i ++ )
{
for (int j = i - 1; j >= 0; j -- )
{
dp[i][j] = dp[i - 1][j];
}
for (int j = i; j >= 1; j -- )
{
//printf("%d %d %d %d\n",i,j,b[i] - 'a',dp[i - 1][j - 1] );
if(dp[i - 1][j - 1] == inf)
continue;
dp[i][j] = min(nex[dp[i - 1][j - 1] + 1][b[i] - 'a'],dp[i][j]);
if(dp[i][j] <= r)
ans = max(j,ans);
}
}
// for (int i = 1; i <= m; i ++ )
// {
// for(int j = 1; j <= i; j ++ )
// printf("%d ",dp[i][j]);
// printf("\n");
// }
// cout<<ans<<endl;
printf("%d\n",r - l + 1 + m - ans * 2);
}
}
}