zoukankan      html  css  js  c++  java
  • FFT字符串匹配

    众所周知$FFT$是一个功能多但是不开$O2$常数吓人的算法。

    这里介绍一下$FFT$如何搞字符串匹配。

    其实我第一次是字符暴力匹配$52$次,结果$T$了一下午。

    后来上网找发现有个更好的算法。

    如果有两个数判相等,我们可以相减,判断是否为$0$;

    但是字符串匹配相当于多对数判相等,相减加和肯定不行,搞成绝对值再相加就行了。

    关键是绝对值有点恶心。

    所以我们不取绝对值取平方

    比如文本串$a$,模式串$b$,

    我们要判断的是$sum((a[k+i]-b[i])^2)==0$,

    把它打开,结果是$sum((a[k+i])^2)+sum((b[i])^2)-2*sum(a[k+i]*b[i])$。

    前边两项预处理可以$O(1)$求,后面那个反转$b$后就是卷积。

    于是求一次卷积,然后带入判断结果是否为$0$即可。

    不开$O2$,$NTT$常数比较小。

    时间复杂度$O(nlogn)$。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N = 1050000;
    const int MOD = 998244353;
    int _id(char c)
    {
        if(c>='a'&&c<='z')return (c-'a'+1);
        return (27+c-'A');
    }
    int to[4*N],lim=1,l;
    ll fastpow(ll x,int y)
    {
        ll ret = 1;
        while(y)
        {
            if(y&1)ret=ret*x%MOD;
            x=x*x%MOD;
            y>>=1;
        }
        return ret;
    }
    ll inv,W[4*N];
    void ntt(ll *a,int len,int k)
    {
        for(int i=0;i<len;i++)
            if(i<to[i])swap(a[i],a[to[i]]);
        for(int i=1;i<len;i<<=1)
        {
            ll w0 = W[i];
            for(int j=0;j<len;j+=(i<<1))
            {
                ll w = 1;
                for(int o=0;o<i;++o,w=w*w0%MOD)
                {
                    ll w1 = a[j+o],w2 = a[j+o+i] * w%MOD;
                    a[j+o] = (w1+w2)%MOD;
                    a[j+o+i] = (w1-w2+MOD)%MOD;
                }
            }
        }
        if(k==-1)
        {
            for(int i=1;i<(len>>1);i++)swap(a[i],a[len-i]);
            for(int i=0;i<len;++i)a[i]=a[i]*inv%MOD;
        }
    }
    char s1[N],s2[N];
    int l1,l2;
    ll ss1[N],ss2,f[N];
    ll a[4*N],b[4*N],c[4*N];
    int main()
    {
        scanf("%s%s",s1,s2);
        l1 = strlen(s1);
        l2 = strlen(s2);
        ss1[0]=_id(s1[0])*_id(s1[0]);
        for(int i=1;i<l1;++i)ss1[i] = ss1[i-1] + _id(s1[i])*_id(s1[i]);
        for(int i=0;i<l2;++i)ss2 = ss2 + _id(s2[i])*_id(s2[i]);
        while(lim<=(l1+l2))lim<<=1,l++;
        for(int i=1;i<lim;++i)to[i] = ((to[i>>1]>>1)|((i&1)<<(l-1)));
        for(int i=0;i<l1;++i)a[i] = _id(s1[i]);
        for(int i=0;i<l2;++i)b[i] = _id(s2[l2-i-1]);
        inv = fastpow(lim,MOD-2);
        for(int i=1;i<lim;i<<=1)W[i] = fastpow(3,(MOD-1)/(i<<1));
        ntt(a,lim,1),ntt(b,lim,1);
        for(int i=0;i<lim;++i)c[i]=a[i]*b[i]%MOD;
        ntt(c,lim,-1);
        for(int i=l2-1;i<l1;++i)f[i]=c[i];
        int ans = 0;
        if(ss1[l2-1]+ss2-2*f[l2-1]==0)++ans;
        for(int i=1;i+l2-1<l1;++i)if(ss1[i+l2-1]-ss1[i-1]+ss2-2*f[i+l2-1]==0)++ans;
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    java基础部分的一些有意思的东西。
    antdvue按需加载插件babelpluginimport报错
    阿超的烦恼 javaScript篇
    .NET E F(Entity Framework)框架 DataBase First 和 Code First 简单用法。
    JQuery获得input ID相同但是type不同的方法
    gridview的删除,修改,数据绑定处理
    jgGrid数据格式
    Cannot read configuration file due to insufficient permissions
    Invoke action which type of result is JsonResult on controller from view using Ajax or geJSon
    Entity model数据库连接
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10284340.html
Copyright © 2011-2022 走看看