UVA-257
本題意義是給你一堆字元串,将其中具有兩個長度超過3的回文串的字元串輸出
要求這兩個回文字元串不能完全覆寫,但是可以重合,而且這兩個回文字元串不能相同。
由于要求長度大于3而且可以重合,我們隻要求每個長度為3/4的回文串就可以了,當某個位置存在長度>=3的回文串,如果串長為奇數,那麼就取3,否則取4,然後把周遊指針i往後挪一位(去掉覆寫的情況),之後用hash判重就可以了。
比如AAAA
我們找到第一個AAA 然後把i++,這樣就避免了AAAA覆寫AAA的情況
因為我們隻考慮長度為3/4的回文串,是以隻考慮這一種覆寫情況即可。
求某個位置為中心回文串的長度時,可以用manacher算法來計算出每個位置的回文半徑。
UVA-257代碼
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<sstream>
#include<map>
using namespace std;
typedef unsigned long long ull;
const int maxn=;
char s[maxn];
map<ull,int> mp;
char Ma[maxn*];
int Mp[maxn*];
string line;
string str;
ull hash_[maxn],xp[maxn];
void init()
{
xp[]=;
for(int i=;i<maxn;i++)
xp[i]=xp[i-]*;
return ;
}
void make_hash(char str[])
{
int len=strlen(str);
hash_[len]=;
for(int i=len-;i>=;i--)
{
hash_[i]=hash_[i+]*+str[i]-'A'+;
}
return ;
}
ull Get_hash(int i,int L)
{
return hash_[i]-hash_[i+L]*xp[L];
}
void Manacher(char s[],int len)
{
int l=;
Ma[l++]='$';
Ma[l++]='#';
for(int i=; i<len; i++)
{
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=;
int mx=,id=;
for(int i=; i<l; i++)
{
Mp[i]=mx>i?min(Mp[*id-i],mx-i):;
while(Ma[i+Mp[i]]==Ma[i-Mp[i]])
Mp[i]++;
if(i+Mp[i]>mx)
{
mx=i+Mp[i];
id=i;
}
}
}
int main()
{
int ans=;
init();
while(scanf("%s",s)!=EOF)
{
mp.clear();
int len=strlen(s);
make_hash(s);
Manacher(s,len);//manacher之後,Mp[i]-1為i位置的回文半徑
int cnt=;
for(int i=;i<*len+;i++)
{
if(Mp[i]->=)
{
if(Mp[i]%==)//回文串為偶數,取長度四的回文串
{
int st=(i-)/-;
int le=;
ull tmp=Get_hash(st,le);
mp[tmp]++;
}
else//回文串為奇數,取長度三的回文串
{
int st=i/-;
int le=;
ull tmp=Get_hash(st,le);
mp[tmp]++;
}
i++;//目前位置存在大于三的回文串,避免覆寫後移一位。
}
}
if(mp.size()>=) printf("%s\n",s);
}
return ;
}