• 扩展KMP(讲解+模版+例题)


    在阅读这篇文章之前,我们假定你已经掌握了KMP:n+1次探里的定义。

    引入:扩展KMP是干什么的

    扩展KMP解决的是源串S的每一个后缀与模式串P的最长公共前缀的长度的问题,并求解出答案extend数组,例如,ababac与aba的extend数组是3 0 3 0 1 0,这里extend[i]表示s[i:5](i从0开始)与p[0:2]的最长公共前缀的长度。

    next数组的定义

    这里的next数组与KMP里的不同。

    next[i]表示从i开始的p的后缀与p的最长公共前缀的长度,也就是,p对p求扩展KMP,可以参见2019 Multi-University Training Contest 5 - 1006 - string matching

    我们先假设已经有了next数组,来求extend,因为next数组的求法是和extend一样的。

    扩展KMP

    递推:已知extend[i-1],如何求extend[i]?

    我们假设在前面匹配时,向右匹配到的最远坐标为last,是从first开始匹配的,也就是说s[first:last]=p[0:last-first]。可以推出s[i:last]=p[i-first:last-first],但这个不是和p的开头匹配,还不能用,我们取extend[i]=min(last-i+1, next[i-first]),看看p[i-first:last-first]和p开头有多少相同。然后向后检测extend[i]能不能更大,这一块暴力,别忘了最后更新first和last。

    初始:暴力大法好

    暴力检测s和p最大公共前缀长度extend[0]。

    求next数组

    和上面一样。next的0位置必定是p的长度,代码中last初值设为0是为了避免初始化。

    例题

    hdu2328

    给一堆字符串,求最长公共字串。

    找一个最短的串,暴力求出每一个后缀,和所有串匹配,找到每个extend里最大的,取总体最小,是一个答案,找到所有答案里长度最长的字典序最小的,就是答案。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<string>
    #include<iostream>
    #define ll long long
    #define db double
    #define ioss ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    using namespace std;
    int n,cnt;
    ll ext[220],nex[220];
    string skr[4020];
    string ans[4020];
    void getNext(string &strp,ll nextt[]){
        ll pl=strp.size();
        ll fir=0,las=0;
        nextt[0]=pl;
        for(ll i=1;i<pl;i++) {
            nextt[i] = min(las - i + 1, nextt[i - fir]);
            if (nextt[i] < 0) nextt[i] = 0;
            while (i+nextt[i]<pl && strp[nextt[i]] == strp[i + nextt[i]]) {
                nextt[i]++;
            }
            if (i + nextt[i] - 1 > las) {
                las = i + nextt[i] - 1;
                fir = i;
            }
        }
    }
    void exKMP(string &strp,string &strs,ll nextt[],ll extt[]){
        //cout<<"start exKMP:"<<endl;
        getNext(strp,nextt);
        ll pl=strp.size(),sl=strs.size();
        ll fir=0,las=-1,mnl=min(sl,pl);
        //cout<<strp<<endl<<strs<<endl;
        while(las<mnl-1&&strp[las+1]==strs[las+1]){
            las++;
            //cout<<"init++"<<endl;
        }
        extt[0]=las+1;
        for(ll i=1;i<sl;i++){
            extt[i]=min(las-i+1,nextt[i-fir]);
            if(extt[i]<0) extt[i]=0;
            while(extt[i]<pl && i+extt[i]<sl && strp[extt[i]]==strs[i+extt[i]]){
                extt[i]++;
            }
            if(i+extt[i]-1>las){
                las=i+extt[i]-1;
                fir=i;
            }
        }
    }
    int main() {
        //ioss;
        //freopen("1.in","r",stdin);
        //freopen("2.out","w",stdout);
        while(scanf("%d",&n)==1&&n){
            cnt=0;
            int mnlen=300,mnlenx;
            for(int i=1;i<=n;i++) {
                cin >> skr[i];
                if (skr[i].size() < mnlen) {
                    mnlen = skr[i].size();
                    mnlenx = i;
                }
            }
            for(int i=0;i<skr[mnlenx].size();i++){
                ll mn=1e10;
                string cur=skr[mnlenx].substr(i);
                //out<<i+1<<": cur= "<<cur<<endl;
                for(int j=1;j<=n;j++){
                    ll mx=0;
                    exKMP(cur,skr[j],nex,ext);
                    /*cout<<"nex: ";
                    for(int k=0;k<cur.size();k++){
                        cout<<nex[k]<<' ';
                    }
                    cout<<endl;
                    cout<<"ext: ";*/
                    for(int k=0;k<skr[j].size();k++){
                        //cout<<ext[k]<<' ';
                        mx=max(mx,ext[k]);
                    }
                    //cout<<endl;
                    mn=min(mn,mx);
                    //cout<<"mn = "<<mn<<endl;
                }
                if(mn>0){
                    if(cnt==0||(mn==ans[1].size())){
                        ans[++cnt]=cur.substr(0,mn);
                    }
                    else if(mn>ans[1].size()){
                        cnt=0;
                        ans[++cnt]=cur.substr(0,mn);
                    }
                }
            }
            if(cnt){
                sort(ans+1,ans+1+cnt);
                cout<<ans[1]<<endl;
            }
            else cout<<"IDENTITY LOST"<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    csps模拟测试70
    模拟测试66反思
    csps63总结
    csps60爆零记
    csps模拟测试57
    模拟测试52,53反思
    LOJ2542「PKUWC2018」随机游走
    LOJ6300 BZOJ5283 [CodePlus 2018 3 月赛]博弈论与概率统计
    2019暑假集训
    省队二轮集训笔记
  • 原文地址:https://www.cnblogs.com/sz-wcc/p/11331361.html
Copyright © 2020-2023  润新知