问题 A: Passward
时间限制: 1 Sec 内存限制: 512 MB题目描述
你来到了一个庙前,庙牌上有一个仅包含小写字母的字符串 s。
传说打开庙门的密码是这个字符串的一个子串 t,并且 t 既是 s 的前缀又是 s 的后缀并且还在 s 的中间位置出现过一次。
如果存在这样的串,请你输出这个串,如有多个满足条件的串,输出最长的那一个。
如果不存在这样的串,输出"Just a legend"(去掉引号)。
输入格式:
仅一行,字符串 s。
输出格式:
如题所述
样例输入
fixprefixsuffix
样例输出:
fix
数据范围:
对于 60%的数据, s 的长度<=100
对于 100%的数据, s 的长度<=100000
输入
做这道题时好迷啊。。首先,可以用HASH逐位比较,其次可以用KMP求出next从尾部向前找,然而,联考时。。我打的大模拟,暴力枚举结果AC了。。数据太水了。。
暴力押正解,乱搞保平安。。(安慰ljy QWQ)
我的暴力
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#define ll long long
using namespace std;
int read()
{
int sum=0,f=1;char x=getchar();
while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
while(x>='0'&&x<='9'){sum=sum*10+x-'0';x=getchar();}
return sum*f;
}
char s[100005];
int len,nex[100005];
int get(int k,int j)
{
if(j==len-1)return 0;
for(int i=1;i<=k;i++)
{
if(s[len-i]!=s[k-i])
return 0;
}
return 1;
}
int main()
{
freopen("fool.in","r",stdin);
freopen("fool.out","w",stdout);
int n;
cin>>n;
while(n--)
{
scanf("%s",s);
len=strlen(s);
int p=-1;
for(int i=1;i<len;i++)
{
if(s[i]==s[0])
{
int j=i,k;
while(j<len&&s[j]==s[j-i])
{ j++;
k=j-i+1;
if(get(k,j))p=max(p,k);
}
if(j!=len)j--;
k=j-i+1;
if(get(k,j))p=max(p,k);
}
}
if(p==-1)
{printf("---\n");return 0;}
for(int i=0;i<p;i++)
printf("%c",s[i]);
printf("\n");
}
}
正解
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int sj=100010;
char s[sj];
int len,nt[sj]={0},p;
bool cx[sj]={0};
void gn()
{
nt[1]=nt[0]=0;
for(int i=2,k=0;i<=len;i++)
{
while(k&&s[i-1]!=s[k]) k=nt[k];
if(s[i-1]==s[k]) k++;
nt[i]=k;
if(i!=len) cx[nt[i]]=1;
}
}
int main()
{
//freopen("t1.txt","r",stdin);
freopen("fool.in","r",stdin);
freopen("fool.out","w",stdout);
scanf("%d",&p);
for(int l=1;l<=p;l++)
{
scanf("%s",s);
len=strlen(s);
memset(cx,0,sizeof(cx));
gn();
int jg=nt[len];
while(jg&&!cx[jg])
jg=nt[jg];
if(jg==0) printf("---");
else
for(int i=0;i<jg;i++)
printf("%c",s[i]);
printf("\n");
}
//while(1);
return 0;
}