题意:
给一个字符串S,将字符串S分成两段,每段字符串如果是回文则获得该段字符串的价值和如果不是回文则此段字符串价值为0。求分割字符串可以获得的最大价值。
思路:
定义字符串T为字符串S的逆序串,比如S:abcaaa T:aaacba
以S为母串T为子串求解扩展KMP,可以发现若Ex1[i]+i==len则S[i,...,len-1]是一个回文串
以T为母串S为子串求解扩展KMP,可以发现若Ex2[i]+i==len则S[0,...,len-i-1]是一个回文串
C++代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 500010;
const int inf = 0x3f3f3f3f;
int Price[30],Sum[maxn],Next[maxn],Ex1[maxn],Ex2[maxn];
void GetNext( char *s , int *Next )
{
int c = 0,len = strlen(s);
Next[0] = len;
while( s[c]==s[c+1]&&c+1<len ) c++;
Next[1] = c;
int po = 1;
for ( int i=2 ; i<len ; i++ )
{
if ( Next[i-po]+i<Next[po]+po )
Next[i] = Next[i-po];
else
{
int t = Next[po]+po-i;
if ( t<0 ) t = 0;
while( i+t<len&&s[t]==s[i+t] ) t++;
Next[i] = t;
po = i;
}
}
}
void ExKmp( char *s1 , char *s2 , int *Next , int *Ex )
{
int c = 0,len = strlen(s1),l2 = strlen(s2);
GetNext( s2 , Next );
while( s1[c]==s2[c]&&c<len&&c<l2 ) c++;
Ex[0] = c;
int po = 0;
for ( int i=1 ; i<len ; i++ )
{
if ( Next[i-po]+i<Ex[po]+po )
Ex[i] = Next[i-po];
else
{
int t = Ex[po]+po-i;
if ( t<0 ) t = 0;
while( i+t<len&&t<l2&&s1[i+t]==s2[t] ) t++;
Ex[i] = t;
po = i;
}
}
}
char S[maxn],T[maxn];
int main()
{
int cas; scanf ( "%d" , &cas );
while ( cas-- )
{
for ( int i=0 ; i<26 ; i++ )
scanf ( "%d" , &Price[i] );
scanf ( "%s" , S );
int len = strlen(S);
for ( int i=0 ; i<len ; i++ )
{
T[i] = S[len-i-1];
if ( i==0 ) Sum[i] = Price[S[i]-'a'];
else Sum[i] = Sum[i-1]+Price[S[i]-'a'];
}
T[len] = '\0';
ExKmp( S , T , Next , Ex1 );
ExKmp( T , S , Next , Ex2 );
int ans = -inf;
for ( int i=1 ; i<len ; i++ )
{
int tmp = 0;
if ( i+Ex1[i]==len )
tmp += Sum[len-1]-Sum[i-1];
if ( len-i+Ex2[len-i]==len )
tmp += Sum[i-1];
ans = max ( ans , tmp );
}
printf ( "%d\n" , ans );
}
return 0;
}