题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5785
思路:
1.L[i]表示以i开始的所有回文的结束位置和,R[i]表示以i位置结尾的所有回文开始位置和,则答案为sigma(R[i-1]*L[i])(x1*y1+x1*y2+...x1*yn+x2*y1+x2*y2+.....x2*yn+......=(x1+x2+....xn)*y1+(x1+x2+...+xn)*y2+......=(x1+x2+.....+xn)*(y1+y2+....+ym))。
2.首先使用Manacher算法求出以每个字母i为对称轴的回文半径pos[i]。对于L:则对应i,字符串[i-pos[i],i+pos[i]]、[i-pos[i]+1,i+pos[i]-1]、[i-pos[i]+2,i+pos[i]-2]、.......、[i,i]为回文串,对应位置i-pos[i]应加上i+pos[i]、i-pos[i]+1应加上i+pos[i]-1、.....、i应加上i。即为对应每一个区间[i-pos[i],i]依次加上以i+pos[i]为首项,-1为公差的等差数列。R数组同理。
3.若对区间[l,r]加上同一个数x,则只需设置标记:对应首项a[l]+=x,尾项a[r+1]-=x,依次递推即可。若对区间加上一首项为x,公差为d的一等差数列,则需设置一数组sub,表示每项的增量。设置a[l]+=x,a[r+1]-=等差数列尾项,sub[l]+=-d,sub[r+1]+=d。依次递推出增量sub[i]+=sub[i-1],对于每项a[i],a[i]+=a[i-1]-sub[i]。
4.由于数组操作为添加符号之后的字符串,则对于原串ansL[i]=L[i]/2,ansR[i]=R[i]/2。由于最终结果取模,此处应乘以逆元500000004(错了好久。。。。)。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug
using namespace std;
typedef long long LL;
const int inv=500000004;
const int mod=1000000007;
const int maxn=2000000+5;
int l;
LL Mp[maxn];
LL L[maxn],subL[maxn];
LL R[maxn],subR[maxn];
char Ma[maxn],st[maxn];
LL ansL[maxn],ansR[maxn];
void Manacher(char s[],int len)
{
l=0;
Ma[l++]='$';
Ma[l++]='#';
for(int i=0; i<len; i++)
{
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=0;
for(int i=0;i<=l;i++) Mp[i]=0;
LL mx=0,id=0;
for(int i=0; i<l; i++)
{
Mp[i]=mx>i?min(Mp[2*id-i],mx-i):1;
while(Ma[i+Mp[i]]==Ma[i-Mp[i]]) Mp[i]++;
if(i+Mp[i]>mx)
{
mx=i+Mp[i];
id=i;
}
}
}
void solve()
{
for(int i=0; i<=l; i++)
{
L[i]=R[i]=subL[i]=subR[i]=0;
}
for(int i=1; i<l; i++)
{
Mp[i]--;
L[i-Mp[i]]+=i+Mp[i];
L[i+1]-=i;
subL[i-Mp[i]+1]+=1;
subL[i+1]-=1;
R[i+Mp[i]]+=i-Mp[i];
R[i-1]-=i;
subR[i+Mp[i]-1]-=1;
subR[i-1]+=1;
}
for(int i=l-1; i>=1; i--)
{
subR[i]+=subR[i+1];subR[i]%=mod;
R[i]+=R[i+1]-subR[i]+mod;R[i]%=mod;
}
for(int i=1; i<l; i++)
{
subL[i]+=subL[i-1];subL[i]%=mod;
L[i]+=L[i-1]-subL[i]+mod;L[i]%=mod;
}
int cnt=0;
for(int i=2; i<l; i+=2)
{
ansL[++cnt]=L[i]*inv%mod;
ansR[cnt]=R[i]*inv%mod;
}
LL ans=0;
for(int i=2; i<=cnt; i++)
{
ans+=(LL)ansR[i-1]*(LL)ansL[i];
ans%=mod;
}
printf("%lld\n",ans);
}
int main()
{
#ifdef debu
freopen("in.txt","r",stdin);
freopen("out.out","w",stdout);
#endif // debug
while(scanf("%s",st)!=EOF)
{
Manacher(st,strlen(st));
solve();
}
return 0;
}