[题意]
给定字符串s,找所有的三元组i,j,k满足s[i,j]以及s[j+1,k]均为回文串,求所有满足条件的三元组的i*k的和。
[分析]
回想起以前刷回文树专题时做过的一道题HDU 5157,求不重叠回文子串的对数,做法类似
回文树中,num[now]表示添加该字符后新产生的回文串个数,即以该字符为结尾的回文串个数,num[now] = num[fail[now]]+1
正着跑一次,同时求出num的前缀和,再反着跑一次,同时累加prefixSum[i-1]*suffixSum[i]即可
这道题中则要求以该字符为结尾的回文串的起始坐标和,不方便直接维护和递推
后来想到,sum[now]表示以该字符为结尾的回文串长度和,则sum[now] = sum[fail[now]] + len[now]
则 (pos[now]+1)*num[now] - sum[now] 即是起始坐标和,反着跑时也可以类似的求出终止坐标和,相乘累加即可
这题有点卡空间,把LL改为int,删掉没用的cnt数组后,刚好卡过
感觉manacher做法有点恶心就没敢写,以后抽空补掉吧。
[代码]
#include <bits/stdc++.h>
using namespace std ;
const int N = 1e6 + 5 ;
const int C = 26 ;
const int mod = 1000000007 ;
typedef long long LL ;
int go[N][C] , fail[N] , len[N] , S[N] ;
int num[N] , sum[N] , suf[N] ;
int last , n , tot ;
int newNode( int x )
{
memset(go[tot],0,sizeof(go[tot])) ;
num[tot] = sum[tot] = 0 ;
len[tot] = x ;
return tot++ ;
}
void init()
{
tot = n = last = 0 ;
newNode(0) ;
newNode(-1) ;
S[n] = -1 ;
fail[0] = 1 ;
}
int getFail( int x )
{
while( S[n-len[x]-1] != S[n] ) x = fail[x] ;
return x ;
}
void insert( int x , int v )
{
S[++n] = x ;
int p = getFail(last) ;
if( !go[p][x] )
{
int now = newNode(len[p]+2) ;
fail[now] = go[getFail(fail[p])][x] ;
num[now] = num[fail[now]] + 1 ;
sum[now] = (sum[fail[now]] + len[now]) % mod ;
go[p][x] = now ;
}
last = go[p][x] ;
}
void build( char *s )
{
init() ;
for( LL i = 0 ; s[i] ; i++ )
{
insert(s[i]-'a',i+1) ;
suf[i+1] = (num[last]*(i+2)%mod - sum[last] + mod) % mod ;
}
}
char s[N] ;
int main()
{
while( ~scanf( "%s" , s ) )
{
int len = strlen(s) ;
build(s) ;
LL ans = 0 ;
init() ;
for( LL i = len-1 ; i >= 0 ; i-- )
{
insert(s[i]-'a',i+1) ;
ans += suf[i]*(num[last]*i%mod + sum[last]) ;
ans %= mod ;
}
printf( "%I64d\n" , ans ) ;
}
return 0 ;
}