https://ac.nowcoder.com/acm/contest/908/H
题意:就是求两个串的最长公共回文子串;
做法:当时那道题撒逼了,以为是一道后缀数组题,结果写了一个小时没写出来,但不过又有人用后缀数组过了,果然自己太弱了。后来想到了马拉车和哈希,这个思路是正确的。就是对任意一个串进行马拉车。找出来他的每个位置的最长回文子串,然后公共回文子串的长度只能其中的一些公共回文子串的长度L,L-2,L-4等等,然后二分答案加hash进行判断就可以了。
但不过我还是WA了很久,我想到了奇偶回文的情况,但不过还是错了,写得不够好吧。后来我偶然想起曾经看过大佬在字符串中插入一些字符,避免奇偶回文的情况。结果还是改了很久,后来有因为数组开小了错了几发,才过了。总结这道题看似简单其实并不简单,还有很多的坑。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=100010;
char s[N<<1],ss[N<<1],s1[N],s2[N],str[N<<2];
int p[N<<2],len1,len2,tot;
ull hash1[N<<1],hash2[N<<1],po[N<<1];
ull geths1(int l,int r)
{
if(l==0)
return hash1[r];
return hash1[r]-hash1[l-1]*po[r-l+1];
}
ull geths2(int l,int r)
{
if(l==0)
return hash2[r];
return hash2[r]-hash2[l-1]*po[r-l+1];
}
int manacher(int len)
{
int id=0,mx=0,m_len=0;
for(int i=2; i<len; i++)
{
if(mx>i)
p[i]=min(p[2*id-i],mx-i);
else
p[i]=1;
while(str[i+p[i]]==str[i-p[i]])
p[i]++;
if(i+p[i]>mx)
{
mx=i+p[i];
id=i;
}
m_len=max(m_len,p[i]-1);
}
return m_len;
}
unordered_map<ull, int>mp;
int judge(int len)
{
mp.clear();
for(int i=2; i+len-1<tot; i+=2)
{
if(p[i]-1>=len)
{
int id=i/2-1;
mp[geths1(id-len/2,id+len/2)]=1;
}
}
for(int i=0; i+len-1<len2; i++)
{
if(mp[geths2(i,i+len-1)]==1)
return 1;
}
return 0;
}
int main()
{
po[0]=1;
for(int i=1; i<(N<<1); i++)
po[i]=po[i-1]*31;
while(~scanf("%s%s",s1,s2))
{
len1=len2=tot=0;
int l1=strlen(s1);
int l2=strlen(s2);
s[len1++]='A';
for(int i=0; i<l1; i++)
s[len1++]=s1[i],s[len1++]='A';
ss[len2++]='A';
for(int i=0; i<l2; i++)
ss[len2++]=s2[i],ss[len2++]='A';
str[tot++]='$';
str[tot++]='#';
for(int i=0; i<len1; i++)
str[tot++]=s[i],str[tot++]='#';
str[tot]='\0';
hash1[0]=s[0];
for(int i=1; i<len1; i++)
hash1[i]=hash1[i-1]*31+s[i];
hash2[0]=ss[0];
for(int i=1; i<len2; i++)
hash2[i]=hash2[i-1]*31+ss[i];
manacher(tot);
int l=0,r=N,ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(judge(mid<<1|1))
{
ans=(mid<<1|1);
l=mid+1;
}
else
r=mid-1;
}
printf("%d\n",ans>>1);
}
return 0;
}