题目
题意
a,b两个字符串,a长度10^5,b长度20,
两种操作:
1、选择任意字符串,在任意位置增加一个字符;
2、选择任意字符串,在任意位置删除一个字符;
q次询问,每次给出l和r,问对于a[l…r]和b两个字符串,最少需要多少次操作可以使两个字符串相同
题解
首先确定不需要增加操作,考虑修改后两个字符串,对于每个位上的字符:
1、如果两个字符串都在这个位置上做了增加操作,那么这个增加操作为多余的,直接不操作即可;
2、如果其中一个字符串在该位置上做了增加操作,那么原先可以直接在另一个字符串的同一位置做删除操作即可,操作数一致;
由于增加操作是多余的,就很容易确定把两个字符串变成相同的最小操作数:|a|+|b|-2*LCS(a,b)
LCS为两个字符串的最大公共子序列的长度
先对进行预处理出pre数组,pre[i][j] 表示 a[i…n]中 j 字符最早出现的位置
对于每次询问用DP求解a[l…r]和b的LCS
dp[i][j] 表示 b[1…i] 的 LCS 为j的情况下,在a中的最小前缀的位置
dp[i][j]来源有两个:
1、直接通过i的上一个位置,同样LCS长度为j的a的最小前缀得到,即dp[i-1][j];
2、先使用i的上一个位置,LCS长度为j-1的a的最小前缀,即dp[i-1][j-1],此时长度为j-1,我们从a字符串中dp[i-1][j-1] 位置开始,向后找到字符b[i] 最早出现位置就是dp[i][j],即pre[dp[i-1][j-1]+1][b[i]];
由此我们可以得到动态转移方程:
dp[ i ][ j ] = min(dp[ i-1 ][ j ], pre[dp[ i-1 ][ j-1 ]+1][b[ i ]])
求出LCS后代入公式就可以求出最小操作数
具体细节对照代码
代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<iostream>
#include<sstream>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<bitset>
#include<vector>
#include<limits.h>
#include<assert.h>
#define SZ(X) ((int)(X).size())
#define ALL(X) (X).begin(), (X).end()
#define REP(I, N) for (int I = 0; I < (N); ++I)
#define REPP(I, A, B) for (int I = (A); I < (B); ++I)
#define PER(I, A, B) for (int I = B; I >= A; I--)
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define FORS(I, S) for (int I = 0; S[I]; ++I)
#define RS(X) scanf("%s", (X))
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define GET_POS(c,x) (lower_bound(c.begin(),c.end(),x)-c.begin())
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
#define MP make_pair
#define PB push_back
#define MS0(X) memset((X), 0, sizeof((X)))
#define MS1(X) memset((X), -1, sizeof((X)))
#define MSINF(X) memset((X), 0x3f3f3f3f, sizeof((X)))
#define LEN(X) strlen(X)
#define F first
#define S a
using namespace std;
typedef long long ll,LL;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<LL> VL;
typedef vector<PII> VPII;
typedef pair<LL,LL> PLL;
typedef vector<PLL> VPLL;
template<class T> void _R(T &x) { cin >> x; }
void _R(int &x) { scanf("%d", &x); }
void _R(LL &x) { scanf("%lld", &x); }
void _R(double &x) { scanf("%lf", &x); }
void _R(char &x) { scanf(" %c", &x); }
void _R(char *x) { scanf("%s", x); }
void R() {}
template<class T> void _W(const T &x) { cout << x; }
void _W(const int &x) { printf("%d", x); }
void _W(const LL &x) { printf("%lld", x); }
void _W(const double &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
template<class T,class U> void _W(const pair<T,U> &x) {_W(x.F); putchar(' '); _W(x.S);}
void W() {}
template<class T, class... U> void W(const T &head, const U &... tail) { _W(head); putchar(sizeof...(tail) ? ' ' : '\n'); W(tail...); }
#ifdef HOME
#define DEBUG(...) {printf("# ");printf(__VA_ARGS__);puts("");}
#else
#define DEBUG(...)
#endif
#define in freopen("in.txt","r",stdin);
#define out freopen("out.txt","w",stdout);
#define mod 998244353
#define INF 0x3f3f3f3f
#define eps 1e-6L
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
LL C(LL n,LL m){if(m > n) return 0;LL ans = 1;FOR(i,1,m){LL a = (n + i - m) % mod;LL b = i % mod;ans = ans * (a * powmod(b, mod-2) % mod) % mod;}return ans;}
ll gcd(ll x,ll y) {return y?gcd(y,x%y):x;}
const int maxn = 111111;
int len_a, len_b;
int pre[maxn][30];
int dp[30][30];
char a[maxn], b[30];
int sol(int l, int r){
for(int i = 0; i <= len_b; i++){
for(int j = 0; j <= len_b; j++){
dp[i][j] = len_a+1;
}
}
for(int i = 0; i < len_b; i++){
dp[i][0] = l - 1;
}
for(int i = 1; i <= len_b; i++){
for(int j = 1; j <= i; j++){
dp[i][j] = dp[i-1][j];
if(dp[i-1][j-1] < r)
dp[i][j] = min(dp[i][j], pre[dp[i-1][j-1]+1][b[i]]);
}
}
for(int j = len_b; j >= 0; j--){
if(dp[len_b][j] <= r) {
return j;
}
}
return 0;
}
int main(){
int cas;
scanf("%d", &cas);
while(cas--){
a[0] = '#';
b[0] = '#';
scanf("%s%s", a+1, b+1);
len_a = strlen(a) - 1;
len_b = strlen(b) - 1;
for(int i = 1; i <= len_a; i++){
a[i]-='a';
}
for(int i = 1; i <= len_b; i++){
b[i]-='a';
}
int q;
for(int i = 0; i < 26; i++){
pre[len_a+1][i] = len_a+1;
}
for(int i = len_a; i >= 1; i--){
for(int j = 0; j < 26; j++){
pre[i][j] = pre[i+1][j];
}
pre[i][a[i]] = i;
}
scanf("%d", &q);
while(q--){
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", len_b + r - l + 1 - 2 * sol(l, r));
}
}
return 0;
}