題目連接:http://acm.hdu.edu.cn/showproblem.php?pid=5785
【題意】已知一個string s,對於求滿足s[i,j],s[j+1,k]都是迴文串所有i*k的和。
【分析】用Manacher算法獲取迴文串的長度,相應轉換成迴文串半徑。採用題解的方法,計算以i爲起點的所有迴文串終點和cntR[i],以及以i爲終點的所有迴文串起點和cntL[i]。於是答案就是遍歷0到strlen(s)-1計算cntL[i]*cntR[i+1]的和。在計算cntR和cntL的時候,暴力做會超時,利用標記數組O(n)來處理才過的。這裏對cntR的標記進行說明,cntL的標記同理。對於一個迴文串s[l,r],標記sumtag[l]+=r,傳遞時sumtag[l+1]=sumtag[l]-1。由於標記只需要傳到(l+r)/2,所以sum[(l+r)/2+1]-=(l+r)/2-1。考慮到區間重疊的問題,以sumcnt[l]標記覆蓋l的區間個數,於是每次處理時sumcnt[l]++,sum[(l+r)/2+1]--。這樣每次傳遞時改爲sumtag[l+1]=sumtag[l]-sumcnt[l]。(ps:注意中間值的取值,這裏僅作說明不一定正確,同時奇偶長度的串需要分開處理)。
【代碼】
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
#define MAXN 1001000
const int mod=1e9+7;
int p[MAXN*2];
char str[MAXN*2];
LL sumtagR[MAXN];
LL sumcntR[MAXN];
LL sumtagL[MAXN];
LL sumcntL[MAXN];
LL cntL[MAXN];
LL cntR[MAXN];
int len,id;
void init(){
memset(sumtagR,0,sizeof(sumtagR));
memset(sumtagL,0,sizeof(sumtagL));
memset(sumcntR,0,sizeof(sumcntR));
memset(sumcntL,0,sizeof(sumcntL));
len=strlen(str),id=0;
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){
int l,r;
if(p[id]+id>i)
p[i]=min(p[2*id-i],p[id]+id-i);
else
p[i]=1;
while(str[i-p[i]]==str[i+p[i]])
++p[i];
if(id+p[id]<i+p[i])
id=i;
if(str[i]=='#'){
l=i/2-(p[i]-1)/2+1,r=i/2+(p[i]-1)/2;
//printf("%d %d %d %d\n",l,r,i/2+1,i/2);
sumtagR[l]=(sumtagR[l]+r)%mod;
sumtagR[i/2+1]=(sumtagR[i/2+1]-i/2)%mod;
sumcntR[l]++;
sumcntR[i/2+1]--;
sumtagL[r]=(sumtagL[r]+l)%mod;
sumtagL[i/2]=(sumtagL[i/2]-i/2-1)%mod;
sumcntL[r]++;
sumcntL[i/2]--;
}
else{
l=i/2-(p[i]-1)/2,r=i/2+(p[i]-1)/2;
//printf("%d %d %d %d\n",l,r,i/2+1,i/2-1);
sumtagR[l]=(sumtagR[l]+r)%mod;
sumtagR[i/2+1]=(sumtagR[i/2+1]-i/2+1)%mod;
sumcntR[l]++;
sumcntR[i/2+1]--;
sumtagL[r]=(sumtagL[r]+l)%mod;
sumtagL[i/2-1]=(sumtagL[i/2-1]-i/2-1)%mod;
sumcntL[r]++;
sumcntL[i/2-1]--;
}
}
for(int i=1;i<=len;++i){
cntR[i]=sumtagR[i];
sumtagR[i+1]=((sumtagR[i+1]+sumtagR[i]-sumcntR[i])%mod+mod)%mod;
sumcntR[i+1]=(sumcntR[i+1]+sumcntR[i])%mod;
}
for(int i=len;i;i--){
cntL[i]=sumtagL[i];
sumtagL[i-1]=((sumtagL[i-1]+sumtagL[i]+sumcntL[i])%mod+mod)%mod;
sumcntL[i-1]=(sumcntL[i-1]+sumcntL[i])%mod;
}
}
int main(){
while(~scanf("%s",str)){
init();
LL ans=0;
for(int i=1;i<len;++i)
ans=(ans+(cntL[i]*cntR[i+1])%mod)%mod;
cout<<ans<<endl;
}
}