题目:
http://acm.hdu.edu.cn/showproblem.php?pid=5787
题意:
找出所有相邻的回文串,将它们最外侧的端点坐标乘积都加起来,(i,j),(j+1,k) 两个回文串,将所有的i*k加和。
思路:
回文串直接用Manacher求解,然后对于所有的回文串都包含许多小的回文串,例如(i,j)回文串同时代表(i+1,j-1)等许多回文串,所以需要将更新的值看为一个区间,然后将所有区间求和,分别处理每个点作为回文串左右端点的情况,最后乘积求和即可。
代码:
//kopyh
#include <bits/stdc++.h>
#define MOD 1000000007
#define N 2000005
using namespace std;
int n,m,sum,res,flag,tot;
int p[N*2];
int Manacher(char *str)
{
int res=0,ans=0,len=strlen(str);
for(int i=len;i>=0;i--)
{
str[i+i+2] = str[i];
str[i+i+1] = '#';
}
str[0] = '*';
for(int i=2;i<2*len+1;i++)
{
if(p[res]+res > i)
p[i] = min(p[2*res-i],p[res]+res-i);
else
p[i] = 1;
while(str[i-p[i]] == str[i+p[i]])
p[i]++;
if(res+p[res]<i+p[i])res=i;
if(ans<p[i])ans=p[i];
}
return ans-1;
}
char s[N];
long long a1[N],a2[N],b1[N],b2[N],aa[N],bb[N],ta[N],tb[N];
int main()
{
int i,j,k,cas,T,t,x,y,z;
while(scanf("%s",s)!=EOF)
{
n=strlen(s);
Manacher(s);
m=strlen(s);
sum=0;tot=0;
memset(a1,0,sizeof(a1));
memset(b1,0,sizeof(b1));
memset(a2,0,sizeof(a2));
memset(b2,0,sizeof(b2));
memset(ta,0,sizeof(ta));
memset(tb,0,sizeof(tb));
for(i=2;i<m-1;i++)
{
t=p[i]-1;
y=i+t;if(y&1)y--;
x=i-t;if(x&1)x++;
x/=2;y/=2;
int mm=(x+y+1)/2;
a1[mm]+=(y-x)&1?mm-1:mm; a1[mm]%=MOD; ta[mm]++;
a2[y]+=x; a2[y]%=MOD; ta[y]--;
mm = (x+y)/2;
b1[x]+=y; b1[x]%=MOD; tb[x]++;
b2[mm]+=(y-x)&1?mm+1:mm; b2[mm]%=MOD; tb[mm]--;
}
long long x=0,y=0,z=0;
for(i=1,j=0;i<=n;i++)
{
x-=y; x+=MOD; x%=MOD;
x+=a1[i]; aa[i]=x;
x-=a2[i]; y+=ta[i];
}
x=0,y=0,z=0;
for(i=1,j=0;i<=n;i++)
{
x-=y; x+=MOD; x%=MOD;
x+=b1[i]; bb[i]=x;
x-=b2[i]; y+=tb[i];
}
long long res=0;
for(i=2;i<=n;i++)
res = (res+aa[i-1]*bb[i])%MOD;
printf("%I64d\n",res%MOD);
}
return 0;
}
该博客介绍了如何使用Manacher算法解决HDU5785题目的回文串问题。博主详细阐述了题意,并解析了思路,即通过考虑回文串的区间特性来优化求解过程,最后给出了解决问题的代码实现。

1624

被折叠的 条评论
为什么被折叠?



