KMP hdu-4300 Clairewd’s message

来源:互联网 发布:淘宝卫生巾假货 编辑:程序博客网 时间:2024/05/17 23:54

题目链接:

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

题目意思:

给一个26个字母a-z对应的密码,给一个字符串,前面为密码后面为明码,让你找出最短的完整的信息,使前面一段时密码,后面一段时明码,而且不能重叠,中间不能有多的。如果不能找到,自己构造出一个。

解题思路:

next[i]表示前缀密码和后缀明码最大的匹配长度。

注意最后next[n]可能大于n/2此时中间有重叠的地方,需要不断地往前移。

处理一下,一遍就可以搞定。

代码:

#include<iostream>#include<cmath>#include<cstdio>#include<cstdlib>#include<string>#include<cstring>#include<algorithm>#include<vector>#include<map>#include<stack>#include<list>#include<queue>#define eps 1e-6#define INF (1<<30)#define PI acos(-1.0)using namespace std;#define Maxn 110000char save[Maxn],change[27];int next[Maxn],n;char ss[27];void getnext(){   int j=0;   next[1]=0;   for(int i=2;i<=n;i++)   {      while(j>0&&save[j+1]-change[save[i]-'a'])         j=next[j];      if(save[j+1]==change[save[i]-'a'])         j++;      next[i]=j;   }   //printf("%d\n",next[n]);   if(next[n]<n/2)      return ;   int temp=n;   while(next[n]>n/2) //大于一半,一直往前移   {      temp=next[temp];      next[n]=temp;   } //如果恰好有一半,就不用管了,这是最大的   if(next[n]<n/2) //看能否再凑成一个   {      if(save[next[n]+1]==change[save[n]-'a'])         next[n]++;   }   return ;}int main(){   int t;   scanf("%d",&t);   while(t--)   {      scanf("%s%s",change,save+1);      for(int i=0;i<26;i++)         ss[change[i]-'a']=i+'a';      n=strlen(save+1);      getnext();     // printf("next:%d\n",next[n]);      if(n-next[n]==next[n])         printf("%s\n",save+1);      else      {         printf("%s",save+1);         for(int i=next[n]+1;i<=n-next[n];i++)            putchar(ss[save[i]-'a']);         putchar('\n');      }      //printf("%d\n",n);   }   return 0;}


原创粉丝点击