Sample Input
aca aaaaSample Output
3 15
题意: 多组输入,每次给定字符串S(|S|<1e5),求多少对不相交的回文串。
思路:可以用回文树求出以每个位置结尾的回文串数,那么累加得到前缀和; 倒着再做一遍得到每个位置为开头的回文串数,乘正向求出的前缀和即可。
#include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) #define rep2(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int maxn=100010; struct PAT { struct node{ int len,num,fail,son[26]; }t[maxn]; int last,n,tot,s[maxn]; void init() { memset(t,0,sizeof(t)); tot=last=1; n=0; t[0].len=0; t[1].len=-1; t[0].fail=t[1].fail=1; s[0]=-1; } int add(int c){ int p=last; s[++n]=c; while(s[n]!=s[n-1-t[p].len]) p=t[p].fail; if(!t[p].son[c]){ int v=++tot,k=t[p].fail; while(s[n]!=s[n-t[k].len-1]) k=t[k].fail; t[v].fail=t[k].son[c]; t[v].len=t[p].len+2; t[v].num=t[t[v].fail].num+1; t[p].son[c]=v; } last=t[p].son[c]; return t[last].num; } }T; ll ans,sum[maxn];char c[maxn]; int main() { while(~scanf("%s",c+1)){ int N=strlen(c+1); T.init(); ans=0; rep(i,1,N) sum[i]=sum[i-1]+T.add(c[i]-'a'); T.init(); rep2(i,N,1) ans+=sum[i-1]*T.add(c[i]-'a'); printf("%lld\n",ans); } return 0; }