HDU - 4300 - Clairewd’s message (扩展KMP)

HDU - 4300 - Clairewd’s message

S 看成密文,转化成明文 T ,那么答案应该是 S 的后缀与 T 的前缀的最小公共部分。
可以转化为求 S[i...n] T 的最长公共前缀。这样可以用扩展KMP来做。
扩展KMP
扩展KMP解决求 S1[i..n] S2 的最长公共前缀, ext[i] 就是其值。
next[i] 的值为 S2[i...n] S2 的最长公共前置。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
char S[N],T[N];
int nxt[N],ex[N],n;
//① P=nxt[po]+po,即最长能匹配到的地方。
//此时s[0,P-po]=S[po,P]
//那么s[i-po,P-po]=s[i,P]
//注意nxt的定义,可以得到如下结论。
//如果nxt[i-po]+i<P ,即不能延伸P的位置,那么此时nxt是确定的。

//② 如果延伸超过了,那么要重新计算P和po,
//因为s[i-po]=s[i,P],所以只需要从原来的P开始就行了。

//getNext是自己在自己身上求extend
//所以求extend的过程与求Next差不多。
void getNext(char s[])
{
    int i=0,j,po;
    nxt[0]=n;
    while(i+1<n&&s[i]==s[i+1]) ++i;
    nxt[1]=i;
    po=1;
    for(i=2;i<n;++i)
    {
        if(nxt[i-po]+i<nxt[po]+po)
            nxt[i]=nxt[i-po];
        else
        {
            j=max(0,nxt[po]+po-i);
            while(i+j<n&&s[j]==s[j+i]) ++j;
            nxt[i]=j;
            po=i;
        }
    }
}

//求出s1[i,...,n-1]与s2的最长公共前缀
void exkmp(char s1[],char s2[])
{
    int i=0,j,k,po;
    while(s1[i]==s2[i]&&i<n) ++i;
    ex[0]=i;
    po=0;
    for(i=1;i<n;++i)
    {
        if(nxt[i-po]+i<ex[po]+po)
            ex[i]=nxt[i-po];
        else
        {
            j=max(0,ex[po]+po-i);
            while(i+j<n&&j<n&&s1[j+i]==s2[j]) ++j;
            ex[i]=j;
            po=i;
        }
    }
}
char f[30],inv[30];
int main()
{
    int kase;
    scanf("%d",&kase);
    while(kase--)
    {
        scanf("%s",f);
        scanf("%s",S);
        for(int i=0;i<26;++i)
            inv[f[i]-'a']=i+'a';
        n=strlen(S);
        for(int i=0;i<n;++i) T[i]=inv[S[i]-'a'];
        T[n]=0;
        getNext(T);
        exkmp(S,T);
        int L=(n+1)/2;
        for(int i=(n+1)/2;i<n;++i,++L)
            if(ex[i]+i==n) break;
        for(int j=0;j<L;++j) putchar(S[j]);
        for(int j=0;j<L;++j) putchar(inv[S[j]-'a']);
        puts("");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值