HDU 4300 Clairewd’s message(扩展KMP)

HDU 4300 Clairewd’s message(扩展KMP)

http://acm.hdu.edu.cn/showproblem.php?pid=4300

题意:首先有一个字母的转换表,就是输入的第一行的字符串,就是'a'转成第一个字母,'b'转成转换表的第二个字母·······

然后下面一个字符串是密文+明文的形式的字符串。

就是说前后两段是重复的,只不过通过转换表转换了下。

而且后面一段可能不完整。我们现在要找到这个串可能的最短密文+明文.

分析:

       首先串S的最短密文+明文可能就是本身,也就是说S正好可以分成两段,前一段是密文可以通过转换表转成与后半段正好相同的明文.

且密文+明文的长度最长不会超过2*T.(即串S完全是密文)

       由于前半段是密文,后半段是明文.假设输入串为S,我们将S完全映射之后得到串T,然我们用串T作为模式串去匹配串S,调用扩展KMP算法,求出以S[i]为开头的前缀与串T的前缀最多匹配长度.那么只要有一个超过串S一半以上的位置的i,以s[i]为头的前缀与T前缀匹配到底,那么这个i就是S中明文的开始.(仔细想想是不是)

AC代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
const int MAXN=100000+1000;
char S[MAXN],T[MAXN];
int B[MAXN],A[MAXN];
int n,m;
void EKMP()
{
    int j=0;

    while(j+1<m && T[0+j]==T[1+j])
        j++;
    A[1]=j;
    int k=1;
    for(int i=2;i<m;i++)
    {
        int len=k+A[k]-1,L=A[i-k];
        if(L<len-i+1)
            A[i]=L;
        else
        {
            j=max(0,len-i+1);
            while(i+j<m && T[0+j] ==T[i+j])
                j++;
            A[i]=j;
            k=i;
        }
    }
    j=0;
    while(j<n && j<m && S[0+j]==T[0+j])
        j++;
    B[0]=j;
    k=0;
    for(int i=1;i<n;i++)
    {
        int len=k+B[k]-1,L=A[i-k];
        if(L<len-i+1)
            B[i]=L;
        else
        {
            j=max(0,len-i+1);
            while(i+j<n && j<m && S[i+j]==T[j])
                j++;
            B[i]=j;
            k=i;
        }
    }
}
int main()
{
    int kase;
    scanf("%d",&kase);
    while(kase--)
    {
        map<char ,char> mp;
        char str[30];
        scanf("%s%s",str,S);
        int len1=strlen(str);
        m=n=strlen(S);
        for(int i=0;i<len1;i++)
            mp[str[i]]=i+'a';

        for(int i=0;i<n;i++)
            T[i]=mp[S[i]];
        T[n]=0;
        EKMP();
        int i;
        for(i=(n+1)/2;i<n;i++)
            if(i+B[i]==n)
                break;
        for(int j=0;j<i;j++)
            printf("%c",S[j]);
        for(int j=0;j<i;j++)
            printf("%c",mp[S[j]]);
        printf("\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值