题解:
做两遍回文自动机。
第一次预处理
fi
f
i
表示所有回文串
(j,i)
(
j
,
i
)
的
j
j
的和。
第二次根据回文串末尾形成等差数列,维护等差数列的即可更新答案。
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
typedef long long LL;
const int N=1e6+50;
const int mod=1e9+7;
char ch[N];
int n, tot, last, len[N], fail[N], diff[N], slink[N];
LL f[N], sans[N];
map <int,int> son[N];
inline int getfail(int pos,int i) {
while(ch[i-len[pos]-1]!=ch[i]) pos=fail[pos];
return pos;
}
inline void solve() {
for(int i=0;i<=tot;i++)
fail[i]=0, son[i].clear();
len[0]=0; len[1]=-1; fail[0]=1; tot=1;
n=strlen(ch+1);
for(int i=1;i<=n;i++) {
int c=ch[i]-'a';
int now=getfail(last,i);
if(!son[now][c]) {
len[++tot]=len[now]+2;
fail[tot]=son[getfail(fail[now],i)][c];
diff[tot]=(len[tot]-len[fail[tot]]);
slink[tot]=(diff[tot]==diff[fail[tot]]) ? slink[fail[tot]] : fail[tot];
son[now][c]=tot;
} last=son[now][c];
f[i]=0;
for(int v=last; len[v]; v=slink[v]) {
sans[v]=i-len[slink[v]]-diff[v]+1;
if(diff[v]==diff[fail[v]])
sans[v]+=sans[fail[v]];
f[i]+=sans[v];
}
}
last=0; LL ans=0;
for(int i=1;i<=n;i++) {
int c=ch[i]-'a';
int now=getfail(last,i);
last=son[now][c];
for(int v=last; len[v]; v=slink[v]) {
sans[v]=f[i-len[slink[v]]-diff[v]];
if(diff[v]==diff[fail[v]])
sans[v]+=sans[fail[v]];
ans+=sans[v]%mod*i%mod;
}
}
printf("%d\n",ans%mod);
}
int main() {
while(~scanf("%s",ch+1)) solve();
}