zoukankan      html  css  js  c++  java
  • Clairewd’s message ekmp

      给两个串第一个串是翻译表(密文可以通过翻译表翻译成明文),第二个串是由密文+明文组成,前面是密文(完整的),后面是明文(未必完整),问能不能把第二个串补全,输出最短的一种可能。

    一开始 用的string   和每次更新字符进行getnext  

    妥妥的 超时   kmp最好不要用string  速度太慢了

    参考了 kuangbin的做法:

    以s为原串做一次扩展KMP,得到extend数组,extend[i]表示原串以第i开始与模式串的前缀的最长匹配。经过O(n)的枚举,我们可以得到,若extend[i]+i=len且i>=extend[i]时,表示stringB即为该点之前的串,stringA即为该点之前的str串,最后输出即可。

    就是原串和翻译后的串进行一次ekmp  然后进行判断输出即可

    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define LL long long
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    #define inf 0x3f3f3f3f
    #define N 100000+50
    int nex[N];
    int extend[N];
    char p[N];
    char s[N];
    char table[N];
    map<char,char>mp;
    void EKMP(char s[],char t[])//s[]为主串,t[]为模式串
    {
        int i,j,p,l;
        int len=strlen(t);
        int len1=strlen(s);
        memset(nex,0,sizeof(nex));
        memset(extend,0,sizeof(extend));
        nex[0]=len;
        j=0;
        while(j+1<len&&t[j]==t[1+j])j++;
        nex[1]=j;
        int a=1;
        for(int i=2;i<len;i++)
        {
            p=nex[a]+a-1;
            l=nex[i-a];
            if(i+l<p+1)nex[i]=l;
            else
            {
                j=max(0,p-i+1);
                while(i+j<len&&t[i+j]==t[0+j])j++;
                nex[i]=j;
                a=i;
            }
        }
        j=0;
        while(j<len1&&j<len&&s[j]==t[j])j++;
        extend[0]=j;
        a=0;
        for(i=1;i<len1;i++)
        {
            p=extend[a]+a-1;
            l=nex[i-a];
            if(l+i<p+1)nex[i]=l;
            else
            {
                j=max(0,p-i+1);
                while(i+j<len1&&j<len&&s[i+j]==t[j])j++;
                extend[i]=j;
                a=i;
            }
        }
    }
    
    int main()
    {
        int cas;
        RI(cas);
        while(cas--)
        {
            RS(table);
            RS(s);
            rep(i,0,25)
            mp[table[i]]='a'+i;
            int len=strlen(s);
            rep(i,0,len-1)
            p[i]=mp[ s[i] ];
            EKMP(s,p);
            int k;
            for(k=(len+1)/2;k<len;k++)
            {
                if(extend[k]+k>=len)//+k 意为当前坐标之前有几个字母 直接为k即可
                break;
            }
            rep(i,0,k-1)
            printf("%c",s[i]);
            rep(i,0,k-1)
            printf("%c",mp[s[i]]);
            cout<<endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    抽奖概率算法
    redis启动异常
    php如何快速读取大文件
    nginx反向代理解决跨域
    sublime修改侧边栏字体
    curl
    公众号开发一
    数组
    在windows下用vagrant建立lnmp开发环境
    gets--vs--fgets
  • 原文地址:https://www.cnblogs.com/bxd123/p/10685781.html
Copyright © 2011-2022 走看看