吐槽这题目名取得……
Pro1
为了入侵m*的机器,m__想了很多方法套m的密码。现在他终于得出了一个重要信息:m的密码是一个回文串。m__从m*处套出了若干个字符串,m__想知道对于每个字符串,最少可以在字符串最后加多少个字符,使得新字符串有可能成为密码。
数据范围
对于60%的数据 字符串长度≤103
对于100%的数据 字符串长度≤105 数据组数≤10
输入格式
若干行,每行一个字符串
输出格式
若干行,每行一个回文串
样例
Pro1.in
aaaa
abba
amanaplanacanal
xyz
Pro1.out
aaaa
abba
amanaplanacanalpanama
xyzyx
题解
这题暴力分还是挺多的。暴力么……主要是求最长回文字串嘛……
随便贴一份暴力
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
typedef long long ll;
#define dd c=getchar()
inline ll read(){
ll x=0,f=1;char dd;
for(;!isdigit(c);dd)if(c==‘-‘)f=-1;
for(;isdigit(c);dd)x=(x<<1)+(x<<3)+(c^48);
return x*f;
}
#undef dd
inline void write(ll x){
if(x<0)putchar(‘-‘),x=-x;
if(x>9)write(x/10);putchar(x%10|48);
}
const ll N=1e5+10;
char a[N];ll len;
inline bool check1(ll mid){
for (ll i=1;mid+i<=len;i++)
if (a[mid-i]!=a[mid+i]) return 0;
for (ll j=mid*2-len-1;j>0;j--) putchar(a[j]);
puts("");
return 1;
}
inline bool check(ll mid){
for (ll i=1;mid+i-1<=len;i++)
if (a[mid-i]!=a[mid+i-1]) return check1(mid);
for (ll j=(mid-1)*2-len;j>0;j--) putchar(a[j]);
puts("");
return 1;
}
int main(){
freopen("pro1.in","r",stdin);
freopen("pro1.out","w",stdout);
while (scanf("%s",a+1)!=EOF){
len=strlen(a+1);
printf("%s",a+1);
for (ll i=len>>1;i<=len;i++)
if (check(i)) break;
}return 0;
}
我的wa暴力
#include <cstdio>
#include <cstring>
#include <queue>
#define deb 0
using namespace std;
char a[100005];
queue<int>que;
char t;
inline bool pan(int l,int r)
{
while(l<r)
{
if(a[l]==t) que.push(l);
if(a[l]^a[r])return false;
l++;r--;
}
return true;
}
inline bool pan2(int l,int r)
{
while(l^r)
{
if(a[l]^a[r])return false;
l++;r--;
}
return true;
}
int main()
{
#if !deb
freopen("pro1.in","r",stdin);
freopen("pro1.out","w",stdout);
#endif
while(gets(a))
{
int ttt=0;
int len=strlen(a);
t=a[len-1];
#if deb
putchar(t);
puts("");
#endif
for(int i=0;i<len;++i)
if(t==a[i])
{
if(pan(i,len-1))
{
ttt=i;
break;
}
while(!que.empty())
{
i=que.front();
if(pan2(i,len-1))
{
ttt=i;
goto L1;
}
que.pop();
}
}
L1:;
if(ttt==0)
{
puts(a);
continue;
}
for(int i=0;i<ttt;++i)putchar(a[i]);
for(int i=len-1;i>=0;--i)putchar(a[i]);
puts("");
}
#if !deb
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
蛙的原因是只考虑回文串的字符个数是奇数的状态(只同时向左向右拓展)。
于是,为了防止这个错误,我们可以在每两个字符之间加一个‘#‘或’%‘(反正该一些奇怪的字符)
gets(ch+1);
len=strlen(ch+1);
for(int i=1;i<=len;++i)s[i<<1]=ch[i],s[i<<1|1]=‘#‘;
s[1]=-1,s[len<<1|1]=-2;//赋一些奇怪的字符
len=len<<1|1;//拓展后的len
于是就变成了Manacher算法
#include <cstdio>
#include <cstring>
using namespace std;
char ch[100005],s[200005];
int len,ppp,ok,ans[200005];
int main()
{
freopen("pro1.in","r",stdin);
freopen("pro1.out","w",stdout);
while(gets(ch+1))
{
len=strlen(ch+1);
for(int i=1;i<=len;++i)s[i<<1]=ch[i],s[i<<1|1]=‘#‘;
s[1]=-1,s[len<<1|1]=-2;//赋一些奇怪的字符
len=len<<1|1;//拓展后的len
ans[1]=0;ok=1;ans[len]=1;
int tot=0;
for(int i=2;i<len;++i)
{
ans[i]=(i>ok+ans[ok])?0:ans[(ok<<1)-i];
if(i<=ok+ans[ok]&&i+ans[i]>ans[ok]+ok) ans[i]=ok+ans[ok]-i;
while(s[i-ans[i]-1]==s[i+ans[i]+1])ans[i]++,tot++;
if(i+ans[i]>ok+ans[ok]) ok=i;
}
ppp=len;
for(int i=2;i<len;++i)
if(i+ans[i]==len-1)
{
ppp=i;break;
}
for(int i=1;i<=len;++i) if(!(i&1)) putchar(s[i]);
for(int i=ppp-ans[ppp]-1;i;--i) if(!(i&1)) putchar(s[i]);
puts("");
}
fclose(stdin);fclose(stdout);return 0;
}
让我们再来看看zhaotiesn大佬的玄学做法
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
#define Max 1000005
int n,l,r,mid,num[200],sum[Max];
char s[Max];
bool flag;
inline bool check(int x){
/*for(int i=x+1;i<=((n+x+1)>>1);i++){
if(s[i]!=s[n-i+x+1])return false;
}*/
// cout<<n<<" "<<(n+x)/2<<" "<<(n+x+1)/2<<" "<<x<<endl;
if(sum[n]-sum[(n+x)/2]==sum[(n+x+1)/2]-sum[x]){
for(int i=x+1;i<=((n+x+1)>>1);i++){
if(s[i]!=s[n-i+x+1])return false;
}
return true;
}else return false;
}
int main(){
freopen("pro1.in","r",stdin);
freopen("pro1.out","w",stdout);
srand((int)time(NULL));
for(int i=1;i<=200;i++)num[i]=rand()*rand()^rand()*rand()^rand();
while(scanf("%s",s+1)!=EOF){
n=strlen(s+1);flag=false;
sum[0]=0;
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+num[int(s[i])];
for(int i=0;i<=n;i++){
if(check(i)){
printf("%s",s+1);
for(int j=i;j>=1;j--){
// printf("%c",s[j]);
putchar(s[j]);
}
puts("");
flag=true;
}
if(flag)break;
}
}
return 0;
}