你来到了一个庙前,庙牌上有一个仅包含小写字母的字符串 s。
传说打开庙门的密码是这个字符串的一个子串 t,并且 t 既是 s 的前缀又是 s的后缀并且还在 s 的中间位置出现过一次。
如果存在这样的串,请你输出这个串,如有多个满足条件的串,输出最长的那一个。
如果不存在这样的串,输出"Just a legend"(去掉引号)。
输入格式:
仅一行,字符串 s。
输出格式:
如题所述
样例输入
fixprefixsuffix
样例输出:
fix
数据范围:
对于 60%的数据, s 的长度<=100
对于 100%的数据, s 的长度<=100000
不得不说一下,这道题真的挺水的,当时考试时就是奔60分去的,谁知道一不小心满分了,数据水,不卡我。
他们说这是KMP裸题,我当时也想到了这点,然而上次打KMP还是在一个半月前,有点忘,不敢直接打KMP,因此直接去打的HASH+MP(fail数组)+链表的暴力。
首先先预处理出hash,mp的fail,链表,因为与前缀后缀相等的单词第一个字母一定和首字母相同,因此我们大可对与首字母相同的位置建一个链表,暴力撸一遍即可,真的挺无聊的。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 #include<queue> 8 #include<map> 9 #include<cmath> 10 using namespace std; 11 char s[100005]; 12 int n,a[100005]; 13 int p=12345; 14 unsigned long long xp[100005]; 15 map<int,unsigned long long> ha; 16 int hz[100005],qz[100005],fl[100005]; 17 int main(){ 18 scanf("%s",s); 19 n=strlen(s); 20 for(int i=0;i<n;i++) 21 { 22 a[i+1]=s[i]-‘a‘+1; 23 } 24 xp[0]=1; 25 for(int i=1;i<=n+2;i++) 26 xp[i]=xp[i-1]*p; 27 for(int i=n;i>0;i--) 28 ha[i]=ha[i+1]*p+a[i]; 29 int nw=1; 30 for(int i=2;i<=n;i++) 31 { 32 if(a[i]==a[1]) 33 { 34 hz[nw]=i; 35 qz[i]=nw; 36 nw=i; 37 } 38 } 39 for(int i=2,j=0;i<=n;i++) 40 { 41 while(j&&a[i]!=a[j+1]) j=fl[j]; 42 if(a[i]==a[j+1]) j++; 43 fl[i]=j; 44 } 45 nw=n-fl[n]+1; 46 int ans=0; 47 while(nw) 48 { 49 50 int l=n-nw+1; 51 unsigned long long hs=ha[1]-ha[l+1]*xp[l]; 52 unsigned long long hss=ha[nw]-ha[n+1]*xp[l]; 53 if(hs!=hss) 54 { 55 nw=hz[nw]; 56 continue; 57 } 58 bool yx=1; 59 60 for(int i=hz[1];i<nw;i=hz[i]) 61 { 62 unsigned long long hh=ha[i]-ha[i+l]*xp[l]; 63 if(hh==hs) 64 { 65 ans=l; 66 yx=0; 67 break; 68 } 69 } 70 if(!yx) 71 break; 72 nw=hz[nw]; 73 } 74 if(nw) 75 { 76 for(int i=0;i<ans;i++) 77 cout<<s[i]; 78 } 79 else 80 { 81 printf("Just a legend\n"); 82 } 83 // while(1); 84 return 0; 85 }