CF49E
记字符集大小 \(A=26\)。
我们并不关心一段字符串怎么变化,只关心变化之后能得到什么字母。设 \(f1_{i,j,z}=0/1\) 表示字符串 \(s_1\) 的 \([l,r]\) 子串不可以/可以变成字母 \(z\)。枚举合并点 \(k\),则有
\[f1_{i,j,z} \leftarrow f1_{i,j,z} \operatorname{or} ( f1_{i,k,x} \operatorname{and} f1_{k+1,j,y} \operatorname{and} mp_{x,y,z}),i\le k <j
\]
其中 \(mp_{x,y,z}=0/1\) 表示两个字母 \(x,y\) 不可以/可以合并为 \(z\)。同理对 \(s_2\) 预处理出 \(f2\)。此部分时间复杂度 \(O((n^3+m^3)A^3)\)。
预处理完后,就可以开始比较 \(s_1,s_2\) 了。设 \(f_{i,j}\) 表示 \(s_1,s_2\) 分别到第 \(i,j\) 个位置的共同祖先的最短长度。枚举 \(1\le k <i,1\le l <j\),若 \(s_1\) 的 \([k+1,i]\) 子串与 \(s_2\) 的 \([l+1,j]\) 子串可以得到相同的字符,则 \(f_{i,j}\leftarrow \min(f_{i,j},f_{k,l}+1)\)。初始化 \(f\) 为 \(+\infty\),\(f_{0,0}=0\)。若 \(f_{n,m}\) 为 \(+\infty\) 则无解。此部分时间复杂度 \(O(n^2m^2A)\)。
#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
char a[51],b[51];
int n,m,f[51][51];
bool mp[26][26][26],f1[51][51][26],f2[51][51][26];
int main(){
cin>>a;
cin>>b;
n=strlen(a),m=strlen(b);
for(int i=n;i>=1;i--)a[i]=a[i-1],a[i]-='a';
for(int i=m;i>=1;i--)b[i]=b[i-1],b[i]-='a';
int T;cin>>T;
while(T--){
char x,y,z,op1,op2;
cin>>z>>op1>>op2>>x>>y;
x-='a',y-='a',z-='a';
// cout<<int(x)<<' '<<int(y)<<' '<<int(z)<<endl;
mp[x][y][z]=1;
}
for(int i=1;i<=n;i++)
f1[i][i][a[i]]=1;
for(int i=1;i<=m;i++)
f2[i][i][b[i]]=1;
for(int L=2;L<=n;L++)
for(int i=1;i+L-1<=n;i++){
int j=i+L-1;
for(int k=i;k<j;k++)
for(int x=0;x<26;x++)
for(int y=0;y<26;y++)
for(int z=0;z<26;z++)
f1[i][j][z]|=f1[i][k][x]&f1[k+1][j][y]&mp[x][y][z];
}
// for(int i=1;i<=n;i++)
// for(int j=i;j<=n;j++)
// for(int z=0;z<26;z++)
// cout<<i<<' '<<j<<' '<<z<<' '<<f1[i][j][z]<<'\n';
for(int L=2;L<=m;L++)
for(int i=1;i+L-1<=m;i++){
int j=i+L-1;
for(int k=i;k<j;k++)
for(int x=0;x<26;x++)
for(int y=0;y<26;y++)
for(int z=0;z<26;z++)
f2[i][j][z]|=f2[i][k][x]&f2[k+1][j][y]&mp[x][y][z];
}
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
f[i][j]=inf;
f[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<i;k++)
for(int l=0;l<j;l++)
for(int z=0;z<26;z++)
if(f1[k+1][i][z]&&f2[l+1][j][z])
f[i][j]=min(f[i][j],f[k][l]+1);
if(f[n][m]==inf)cout<<-1;
else cout<<f[n][m];
return 0;
}
我们会走到一起的。

浙公网安备 33010602011771号