hdu4300拓展KMP

输入规则
然后密文+半截明文
求出在哪里中间断开并且使得求出的密文要最短
算法:
拓展kmp,可以将原来的字符串全部回转成明文
也就是变成 明文+(明文的明文)

然后再拓展KMP就行

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1e5;
int Next[maxn+100],extend[maxn+100];
char str1[maxn+100],str2[maxn+100],rule[30],rule_ver[30];
void GetNext(char *str);
void ExKMP(char *s1,char *s2);
int main()
{
    int t,len,ed;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s%s",rule,str1);
        len=strlen(str1);
        ed=len;
        for(int i=0; i<26; i++)
            rule_ver[rule[i]-'a']=i+'a';
        for(int i=0; i<len; i++)
            str2[i]=rule_ver[str1[i]-'a'];
        ExKMP(str1,str2);
        for(int i=(len+1)/2; i<len; i++)
            if(extend[i]==len-i)
            {
                ed=i;
                break;
            }
        for(int i=0; i<ed; i++)
            printf("%c",str1[i]);
        for(int i=0; i<ed; i++)
            printf("%c",str2[i]);
        printf("\n");
    }
    return 0;
}
void GetNext(char *str)
{
    int i=0,j,pos,len=strlen(str);
    Next[0]=len;   //初始化next[0]
    while(i+1<len&&str[i]==str[i+1]) i++; //初始化next[1]
    Next[1]=i;
    pos=1; //初始化pos
    for(i=2; i<len; i++)
    {
        if(i+Next[i-pos]<pos+Next[pos])
            Next[i]=Next[i-pos];
        else
        {
            j=pos+Next[pos]-i;
            if(j<0) j=0;    //如果i>pos+next[pos],则从头开始
            while(i+j<len&&str[i+j]==str[j]) j++;
            Next[i]=j;
            pos=i;
        }
    }
}
void ExKMP(char *s1,char *s2)         //s2的后缀和s1的最长前缀
{
    int i=0,j,pos,len1=strlen(s1),len2=strlen(s2);
    GetNext(s2);
    while(i<len1&&i<len2&&s1[i]==s2[i]) i++;
    extend[0]=i;
    pos=0;
    for(int i=1; i<len1; i++)
    {
        if(i+Next[i-pos]<pos+extend[pos])
            extend[i]=Next[i-pos];
        else
        {
            j=pos+extend[pos]-i;
            if(j<0) j=0;
            while(i+j<len1&&j<len2&&s1[i+j]==s2[j]) j++;
            extend[i]=j;
            pos=i;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值