题意:
定义回文串的度为length 即前半部分串的度或后半部分的度+1。先再给你一个字符串。要你求出他所有前缀度的和。
思路:
先用manacher求出以每个位置为中心最大回文串的长度。dp[i]记录长度为i的前缀的度。那么dp[i+1]分奇偶用到前面的度就行了。
详细见代码:
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=5110000;
int p[maxn<<1],dp[maxn],len;
char buf[maxn],st[maxn<<1];
void init()
{
int i;
len=strlen(buf);
st[0]='$',st[1]='#';
for(i=0;i<len;i++)
st[2*i+2]=buf[i],st[2*i+3]='#';
len=2*len+2;
}
void manacher()
{
int i,id,mx=0;
for(i=1;i<len;i++)
{
p[i]=mx>i?min(mx-i,p[2*id-i]):1;
while(st[i+p[i]]==st[i-p[i]])
p[i]++;
if(i+p[i]>mx)
mx=i+p[i],id=i;
}
}
int main()
{
int i,ans,n;
while(~scanf("%s",buf))
{
ans=0,n=strlen(buf);
init();
manacher();
ans=dp[0]=1;
for(i=1;i<n;i++)
{
if(p[i+2]-1>=i+1)//判断该前缀是否回文。字符串从0开始。i+2为0到i在p数组对称中心不管回文串长度使是奇数还是偶数的。p[i]-1为最大回文长度
{
if(i&1)
dp[i]=dp[i/2]+1;
else
dp[i]=dp[i/2-1]+1;
}
ans+=dp[i];
}
printf("%d\n",ans);
}
return 0;
}
Hash的做法就比较简单了。
详细见代码:
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=5110000;;
unsigned long long H1[maxn],H2[maxn],xp[maxn],ha,hb,x=123;
int dp[maxn],len;
char buf[maxn],rbuf[maxn];
void init()
{
int i;
len=strlen(buf);
H1[len]=H2[len]=0;
xp[0]=1;
for(i=len-1;i>=0;i--)
{
H1[i]=H1[i+1]*x+buf[i];
H2[i]=H2[i+1]*x+rbuf[i];
xp[len-i]=xp[len-i-1]*x;
}
}
unsigned long long getHash(unsigned long long *HS,int s,int L)
{
return HS[s]-HS[s+L]*xp[L];
}
int main()
{
int i,ans;
while(~scanf("%s",buf))
{
ans=0,len=strlen(buf);
for(i=0;i<len;i++)
rbuf[i]=buf[len-i-1];
init();
ans=dp[0]=1;
for(i=1;i<len;i++)
{
ha=getHash(H1,0,i+1);
hb=getHash(H2,len-i-1,i+1);
if(ha==hb)
{
if(i&1)
dp[i]=dp[i/2]+1;
else
dp[i]=dp[i/2-1]+1;
}
else
dp[i]=0;
ans+=dp[i];
}
printf("%d\n",ans);
}
return 0;
}