标签:它的 pre 实现 detail n+1 const war 思路 回文串
字符串,需要把这个字符串分成两段,并使得被分开的两段价值和最大。
一个串如果是回文,那么它的价值就是所有字符的价值和,否则价值为0。每个字母都有相应的价值,这个会给出。
使用Manacher
,我们可以算出每个点的回文串长度,然后我们枚举左半部分的长度(这样很容易算出中心点),进而知道以这个中心点的回文串长度是不是等于这个左半部分的长度。这样来判断。
对于价值,我们可以使用前缀和来提前算好,这样用的话就可以直接用了。下节的代码实现对应这个算法。
搜了一下题解,还有发现使用拓展KMP
也可以,思路上也比较简单。
想要看的话可以点击这个链接:https://blog.csdn.net/u013480600/article/details/23041391
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=5e5+7;
char str[maxn], s[maxn<<1];
int p[maxn<<1], newlen;
int val[26], presum[maxn];
void init(int n)
{
newlen=n<<1;
// s[0]='$';
for(int i=0; i<=newlen+1; i++) s[i]='#';
for(int i=1; i<=n; i++) s[i<<1]=str[i];
s[newlen+2]=0;
}
void manacher()
{
int mx=0,id=0;
for(int i=1;i<=newlen;i++)
{
if(mx>i) p[i]=min(p[2*id-i],mx-i);
else p[i]=1;
while(i-p[i]>=0&&s[i-p[i]]==s[i+p[i]]) p[i]++;
if(i+p[i]>mx)
{
mx=i+p[i];
id=i;
}
}
}
int main()
{
int t=0;
scanf("%d",&t);
while(t--)
{
for(int i=0; i<26; i++) scanf("%d", &val[i]);
scanf("%s", str+1);
int len=strlen(str+1);
presum[0]=0;
for(int i=1; i<=len; i++)
presum[i] = presum[i-1] + val[ str[i]-'a'];
init(len);
manacher();
// for(int i=1; i<=newlen; i++)
// printf("%d ", p[i]);
// printf("\n");
int ans=-inf;
for(int cut=1; cut<len; cut++)
{
int temp=0;
int len1=cut, len2=len-len1;
if(len1%2 == 1)
{
int mid=len1/2+1;
int palen=p[mid<<1]-1; //mid<<1,这里是对应的实际位置
if(len1 == palen) temp+=presum[len1];
}
else
{
int mid=len1/2;
int palen=p[mid*2+1]-1;
if(len1 == palen ) temp+=presum[len1];
}
if(len2%2==1)
{
int mid=len1+len2/2+1;
int palen=p[mid<<1]-1;
if(len2 == palen) temp += presum[len] - presum[len1];
}
else
{
int mid=len1+len2/2;
int palen=p[mid*2+1]-1;
if(len2 == palen ) temp += presum[len] - presum[len1];
}
if(temp>ans) ans=temp;
}
printf("%d\n", ans);
}
return 0;
}
HDU 3613 Best Reward Manacher算法
标签:它的 pre 实现 detail n+1 const war 思路 回文串
原文地址:https://www.cnblogs.com/alking1001/p/12248658.html