[CF954I]Yet Another String Matching Problem

Description

给出两个字符串S和T
定义两个等长的字符串A和B之间的距离为:
每次操作可以选择两个字符c1和c2,将两个字符串中的所有c1替换为c2,这样将A和B变为相等的最小操作次数。
求S的每个长度为|T|的子串和T之间的距离。
n<=125000,保证S和T只含有小写字母a~f

Solution

先考虑怎么求一对字符串的距离
对于每个字符c开一个点,从A中每个字符向B中相同位置的字符连一条无向边
答案就是6-联通块个数,因为不同联通块之间显然不需要耗费操作次数,同一联通块可以用n-1次完成
接下来就很简单了,最多只有30种边,枚举S和T中哪两个字符匹配,接下来就变成了字符串配对问题
FFT即可

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=lst[a];i;i=nxt[i])
using namespace std;

typedef long long ll;

const int N=4e5+5,Mo=998244353;

int pwr(int x,int y) {
    int z=1;
    for(;y;y>>=1,x=(ll)x*x%Mo)
        if (y&1) z=(ll)z*x%Mo;
    return z;
}

void mod(int &x) {x=x>=Mo?x-Mo:x;}

int n,m,len,lg,inv,t[N],f[N],g[N],h[N],W[N],e[N][6][6];
char S[N],T[N];
bool vis[6];

void pre(int N) {
    for(len=1,lg=0;len<N;len<<=1) lg++;
    W[0]=1;W[1]=pwr(3,(Mo-1)/len);
    fo(i,2,len) W[i]=(ll)W[i-1]*W[1]%Mo;
    inv=pwr(len,Mo-2);
}

void DFT(int *a,int flag) {
    for(int i=0;i<len;i++) {
        int p=0;
        for(int j=i,k=0;k<lg;k++,j>>=1) p=(p<<1)+(j&1);
        t[p]=a[i];
    }
    for(int m=2;m<=len;m<<=1) {
        int half=m/2,times=len/m;
        for(int i=0;i<half;i++) {
            int w=(flag>0)?W[i*times]:W[len-i*times];
            for(int j=i;j<len;j+=m) {
                int u=t[j],v=(ll)t[j+half]*w%Mo;
                mod(t[j]=u+v);
                mod(t[j+half]=u+Mo-v);
            }
        }
    }
    for(int i=0;i<len;i++) a[i]=t[i];
    if (flag==-1) for(int i=0;i<len;i++) a[i]=(ll)a[i]*inv%Mo;
}

void dfs(int x,int n) {
    vis[x]=1;
    fo(i,0,5) if (!vis[i]&&e[n][x][i]) dfs(i,n);
}

int main() {
    scanf("%s",S);n=strlen(S);
    scanf("%s",T);m=strlen(T);
    fo(i,0,m/2-1) swap(T[i],T[m-i-1]);
    pre(n+m);
    fo(a,0,5)
        fo(b,0,5) {
            if (a==b) continue;
            fo(i,0,len-1) f[i]=g[i]=0;
            fo(i,0,n-1) f[i]=S[i]-'a'==a;
            fo(i,0,m-1) g[i]=T[i]-'a'==b;
            DFT(f,1);DFT(g,1);
            fo(i,0,len-1) h[i]=(ll)f[i]*g[i]%Mo;
            DFT(h,-1);
            fo(i,m-1,n-1) {
                e[i][a][b]|=h[i]>0;
                e[i][b][a]|=h[i]>0;
            }
        }
    fo(i,m-1,n-1) {
        int ans=6;
        fo(j,0,5) vis[j]=0;
        fo(j,0,5) if (!vis[j]) dfs(j,i),ans--;
        printf("%d ",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/alan_cty/article/details/80369733