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;
}
posted @ 2025-09-12 19:40  FormulaOne  阅读(10)  评论(0)    收藏  举报