0
点赞
收藏
分享

微信扫一扫

HDU 3613 Best Reward(manacher算法)


Best Reward
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 364    Accepted Submission(s): 144

Problem Description
After an uphill battle, General Li won a great victory. Now the head of state decide to reward him with honor and treasures for his great exploit. 

One of these treasures is a necklace made up of 26 different kinds of gemstones, and the length of the necklace is n. (That is to say: n gemstones are stringed together to constitute this necklace, and each of these gemstones belongs to only one of the 26 kinds.) 

In accordance with the classical view, a necklace is valuable if and only if it is a palindrome - the necklace looks the same in either direction. However, the necklace we mentioned above may not a palindrome at the beginning. So the head of state decide to cut the necklace into two part, and then give both of them to General Li. 

All gemstones of the same kind has the same value (may be positive or negative because of their quality - some kinds are beautiful while some others may looks just like normal stones). A necklace that is palindrom has value equal to the sum of its gemstones' value. while a necklace that is not palindrom has value zero. 

Now the problem is: how to cut the given necklace so that the sum of the two necklaces's value is greatest. Output this value. 

 

Input
The first line of input is a single integer T (1 ≤ T ≤ 10) - the number of test cases. The description of these test cases follows. 

For each test case, the first line is 26 integers: v1, v2, ..., v26 (-100 ≤ vi ≤ 100, 1 ≤ i ≤ 26), represent the value of gemstones of each kind. 

The second line of each test case is a string made up of charactor 'a' to 'z'. representing the necklace. Different charactor representing different kinds of gemstones, and the value of 'a' is v1, the value of 'b' is v2, ..., and so on. The length of the string is no more than 500000. 

 

Output
Output a single Integer: the maximum value General Li can get from the necklace.
 

Sample Input

2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 aba 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 acacac

Sample Output
1 6
 

 

题意:

分析:

终于叫我做出来,分析的我差点把纸张撕了。

我们求出标记前缀和后缀是否是回文串,枚举割点就ok。

标记前缀和后缀是否是回文串:manacher算法

本题的位置我退了老半天,

上一个例子:

str:acacac

位置:         0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
 转换字符   @ # a # c # a # c # a # c #
 len[i]:          0 1 2 1 4 1 6 1 6 1 4 1 2 1 0

len[i]:以字符S[i]为中心的最长回文子串向左/右扩张的长度

L: 转换字符的长度

求前缀是否回文:

大家想想红色那一行,len[i]=i代表他的左半部分能扩展到最前面,即这个前缀满足回文,他的位置呢?

(它当前的位置+它最大能向右扩展的位置len[i]-2)/2-1          ( /2-1目的变为原字符串的位置)

(4+4(到达c)-2(达到a))/2-1=2

求后缀是否回文

后缀自然向右扩展,我们如何保证扩展到最后呢?L+1-i=len[i]即可,即这个后缀满足回文,他的位置呢?

(它当前的位置-它最大能向左扩展的位置len[i]+2)/2-1          ( /2-1目的变为原字符串的位置)

还有一个巧妙的处理前缀和,代码一看就知道了

KMP和EXKMP都可以做,回来在补

 

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int maxn=1000010;
char str[maxn];//原字符串
char tmp[maxn<<1];//转换后的字符串
int Len[maxn<<1],val[30];
int pre[maxn],hou[maxn],sum[maxn];
int pos;
//转换原始串
int init(char *st)
{
int i,len=strlen(st);
tmp[0]='@';//字符串开头增加一个特殊字符,防止越界
for(i=1;i<=2*len;i+=2)
{
tmp[i]='#';
tmp[i+1]=st[i/2];
}
tmp[2*len+1]='#';
tmp[2*len+2]='$';//字符串结尾加一个字符,防止越界
tmp[2*len+3]=0;
return 2*len+1;//返回转换字符串的长度
}
//Manacher算法计算过程
int manacher(char *st,int len)
{
int mx=0,ans=0,po=0;//mx即为当前计算回文串最右边字符的最大值
for(int i=1;i<=len;i++)
{
if(mx>i)
Len[i]=min(mx-i,Len[2*po-i]);//在Len[j]和mx-i中取个小
else
Len[i]=1;//如果i>=mx,要从头开始匹配

while(st[i-Len[i]]==st[i+Len[i]])
Len[i]++;
if(Len[i]+i>mx)//若新计算的回文串右端点位置大于mx,要更新po和mx的值
{
mx=Len[i]+i;
po=i;
}

if(i==Len[i]&&Len[i]>1)
pre[(Len[i]+i-2)/2-1]=1;
if(len+1-i==Len[i]&&Len[i]>1)
hou[(i-Len[i]+2)/2-1]=1;

}
return ans-1;//返回Len[i]中的最大值-1即为原串的最长回文子串额长度
}
int main()
{
int T;
cin>>T;
while(T--)
{
memset(pre,0,sizeof(pre));
memset(hou,0,sizeof(hou));
memset(sum,0,sizeof(sum));
for(int i = 0; i < 26; ++i)
scanf("%d",&val[i]);
scanf("%s",&str);
int len=strlen(str);

int l=init(str);

manacher(tmp,l);

for(int i=0;i<len;i++)
{
if(i==0) sum[i]=val[str[i]-'a'];
else sum[i]=sum[i-1]+val[str[i]-'a'];
}
int ans=0;
for(int i=0;i<len-1;i++)
{
int sum1=0,sum2=0;
if(i==0)sum1=1;
if(i+1==len-1)sum2=1;
if(pre[i]==1)sum1=sum[i];
if(hou[i+1]==1)sum2=sum[len-1]-sum[i];
//cout<<sum1<<" "<<sum2<<endl;
ans=max(ans,sum1+sum2);
}
printf("%d\n",ans);
/*for(int i=0;i<=len*2+2;i++)
{
cout<<i<<" ";
}
cout<<endl;
for(int i=0;i<l+1;i++)
cout<<tmp[i]<<" ";
cout<<endl;
for(int i=0;i<=len*2+2;i++)
{
cout<<Len[i]<<" ";
}
cout<<endl;*/

}
}

 

举报

相关推荐

0 条评论