【FFT】Codeforces954I Yet Another String Matching Problem

分析:

又是一道经典的FFT做字符串匹配的问题。
题目要求做一定次数的操作,使得最终所有相匹配的字符一样。

可以将这个字符映射到一个图上,如果这种匹配情况下有一个字符 x 匹配的是 y ,那么就在图中 x 点向 y 点连一条边。最终图中的每个联通块的大小-1就是操作次数。(其实可以用并查集实现,操作次数就是并查集中的合并次数)

所以枚举每一种匹配关系,比如如果考虑 x 字符与 y 字符匹配的情况,则令原串中所有x为1,模式串中所有y为1,将模式串翻转,再卷积。然后再令原串中所有y为1,模式串中所有x为1,再翻转做一次。两种情况得到的结果的和,就表示这种情况的数量,对每一位不为0的,就连上 x y 这条边。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#define SF scanf
#define PF printf
#define MAXN 300000
using namespace std;
typedef long long ll;
int siz;
const double Pi=acos(-1);
struct cpx{
    double r,i;
    cpx() {}
    cpx(double _r,double _i):r(_r),i(_i) {}
    cpx operator * (const cpx &a) const{
        return cpx(r*a.r-i*a.i,r*a.i+i*a.r);
    }
    cpx operator + (const cpx &a) const{
        return cpx(r+a.r,i+a.i);
    }
    cpx operator - (const cpx &a) const{
        return cpx(r-a.r,i-a.i);
    }
};
void fft(cpx *a,int f,int N){
    int i,j,k;
    for(i=1,j=0;i<N;i++){
        for(int d=N;j^=d>>=1,~j&d;);
        if(i<j)
            swap(a[i],a[j]);
    }
    for(i=1;i<N;i<<=1){
        cpx wn(cos(Pi/i),f*sin(Pi/i));
        for(j=0;j<N;j+=i<<1){
            cpx w(1,0);
            for(k=0;k<i;k++,w=w*wn){
                cpx x=a[j+k],y=w*a[i+j+k];
                a[j+k]=x+y;
                a[i+j+k]=x-y;
            }
        }
    }
    if(f==-1)
        for(i=0;i<N;i++)
            a[i].r/=N;
}
cpx A[MAXN],B[MAXN];
int n;
int sum[MAXN],res[MAXN],fa[10][MAXN],len1,len2;
char s1[MAXN],s2[MAXN];
void solve(char x,char y){
    memset(A,0,sizeof A);
    memset(B,0,sizeof B);
    for(int i=0;i<len1;i++)
        if(s1[i]==x)
            A[i].r=1;
    for(int i=0;i<len2;i++)
        if(s2[i]==y)
            B[len2-i-1].r=1;
    fft(A,1,siz);
    fft(B,1,siz);
    for(int i=0;i<siz;i++)
        A[i]=A[i]*B[i];
    fft(A,-1,siz);
    for(int i=0;i<siz;i++)
        res[i]+=int(A[i].r+0.5);
}
int get_fa(int id,int x){
    if(fa[x][id]==0)
        return x;
    fa[x][id]=get_fa(id,fa[x][id]);
    return fa[x][id];
}
void link(int x,int y,int id){
    int u=get_fa(id,x);
    int v=get_fa(id,y);
    if(u!=v){
        fa[u][id]=v;
        sum[id]++;  
    }
}
int main(){
    SF("%s%s",s1,s2);
    len1=strlen(s1);
    len2=strlen(s2);
    siz=1;
    while(siz<=len1+len2)
        siz<<=1;
    for(int i='a';i<='f';i++)
        for(int j='a';j<='f';j++){
            if(i==j)
                continue;
            memset(res,0,sizeof res);
            solve(i,j);
            solve(j,i);
            for(int k=0;k<len1;k++)
                if(res[k]>0)
                    link(i-'a',j-'a',k);    
        }
    for(int i=len2-1;i<len1;i++)
        PF("%d ",sum[i]);
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/80795577
今日推荐