題目地址: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;
}