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

题目链接:
HDU - 4300

题意分析:

单独抽出来一段很重要的话:

​
But GFW knows that Clairewd would always firstly send the ciphertext and then plaintext(Note that they
 won't overlap each other). But he doesn't know how to separate the text because he has no idea about the whole message. 

​

这一段话的意思是:

但是GFW知道Clairewd总是首先发送密文然后发送明文(注意它们不会相互重叠)。但他不知道如何分开文本,因为他不知道整个信息。

也就是说,题目中给出的这一块的数据是由密文和明文组成的!

题目的大致意思就是给出两个字符串,第一个字符串代表密匙,第二个字符串代表由密文和明文组成的串(密文是给出来所有了,但是明文有可能给出一部分,也有可能没有),所以现在我们要先把第二个串按照密文得出一个新字符串,判断这个字符串的密文通过密匙得到的原文是否与原明文相同(有点绕,下面给出一张图),并且把这个串给输出出来。

题解:

 

现在就拿图中第二个样例来说,如果按照给出的密文对应法则,可以得到这个串所对应的串abcdekxvmc。

我们发现,得到得这个串的前一半刚好和原本串的后一部分相同,注意,原本串的后一部分叫做明文,而密文对应的是明文,所以这种情况可以直接输出。

现在把这个串给改变一下:

 

把原本的t改成了y,那么它所对应的字母就相应的变成了f,我们观察到abcde不等于abcdf,也就是说原本的这个串里面全是密文,没有一个是明文!!!!!

现在我们再想一下,如果说上面串的后缀中与下面串的前缀中有相同的呢?

这个图是我为了演示随便给出的一个例子,可以看出,我们可以直接把上面的串给输出,然后再打印后面的字符(后面的字符代表原文,刚好是下面的)

打印的位置应该从 next[] 开始,结束的位置是 总长- next[]

也就是说我们只需要打印图中的1区域即可!

 

AC代码:

#include<cstdio>
#include<algorithm>
#include<string.h>
#include<string>
#include<iostream>
using namespace std;
const int maxn=1e5+10;

int N,nexxt[maxn];
char num1[maxn],num2[maxn];
int num_long2;
int ex_num1[maxn];
char ex_num2[maxn];

void find_next()
{
    nexxt[0]=-1;
    int k=-1;
    int j=0;
    while(j<num_long2)
    {
        if(k==-1||ex_num2[k]==ex_num2[j])
        {
            ++k;
            ++j;
            if(ex_num2[k]!=ex_num2[j])
            {
                nexxt[j]=k;
            }
            else
            {
                nexxt[j]=nexxt[k];
            }
        }
        else
        {
            k=nexxt[k];
        }
    }
}

int print_next()
{
   int i,j=0;
   if(num_long2%2==1)
   {
       i=num_long2/2+1;
   }
   else
   {
       i=num_long2/2;
   }
   while(i<num_long2&&j<num_long2)
   {
       if(j==-1||num2[i]==ex_num2[j])
       {
           ++i;
           ++j;
       }
       else
       {
           j=nexxt[j];
       }
   }
   return j;
}

int main()
{
    cin>>N;
    while(N--)
    {
        scanf("%s %s",num1,num2);
        //其中num代表的是对应规则
        for(int i=0;i<26;++i)
        {
            char word=num1[i];
            ex_num1[word]=i;
            //每个字母对应的数字
        }
        //找到了对应规则,进行第二步计算,变换
        num_long2=strlen(num2);
        for(int i=0;i<num_long2;++i)
        {
            ex_num2[i]='a'+ex_num1[num2[i]];
        }
        //变换完毕,进行计算前后缀长度
        find_next();
        //找到next数组之后,进行判断。
        int longg=print_next();
        if(longg*2==num_long2)
        {
            printf("%s\n",num2);
        }
        else
        {
            printf("%s",num2);
            int number=num_long2-longg;
            for(int i=longg;i<number;++i)
            {
                printf("%c",ex_num2[i]);
            }
            printf("\n");
        }
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值