您的位置:首页 > 其它

扩展KMP --- HDU 3613 Best Reward

2015-05-06 22:37 267 查看

Best Reward

Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=3613

[b]Mean:[/b]

给你一个字符串,每个字符都有一个权值(可能为负),你需要将这个字符串分成两个子串,使得这两个子串的价值之和最大。一个子串价值的计算方法:如果这个子串是回文串,那么价值就是这个子串所有字符权值之和;否则价值为0。

[b]analyse:[/b]

扩展KMP算法运用。
总体思路:
找出所有包含第一个字母的回文串和包含最后一个字母的回文串,然后O(n)扫一遍,每次判断第i个字母之前(包含第i个字母)的子串是否是回文,以及从第i个字母后的子串是否是回文,然后计算出答案,取最大值。
具体做法:
假设输入的字符串是"abcda"
构造串s1="abcda#adcba"
求s1的Next数组,得到了包含第一个字母的回文串的位置;
构造串s2="adcba#abcda"
求s2的Next数组,得到了包含最后一个字母的回文串的位置;
用两个flag数组标记这些位置,然后扫一遍就得答案了。
中间加一个'#'并后接反串的目的是:当整个串都是回文的时候能够被Next数组记录下。

[b]Time complexity: O(nlogn)[/b]

[b]Source code: [/b]

第一遍写,不够优化:

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-05-07-16.26
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  LL long long
#define  ULL unsigned long long
using namespace std;
const int MAXN=500010;
int val[30],Next[MAXN*2],sum[MAXN];
char s[MAXN],s1[MAXN*2];
bool flag[2][MAXN];
void get_sum()
{
int len=strlen(s);
sum[0]=val[s[0]-'a'];
for(int i=1;i<len;++i)
sum[i]=sum[i-1]+val[s[i]-'a'];
}

void get_Next(char ss[])
{
int len=strlen(ss);
Next[0]=0;
int k=0;
for(int i=1;i<len;++i)
{
while(k!=0 && ss[i]!=ss[k])
k=Next[k-1];
if(ss[i]==ss[k]) k++;
Next[i]=k;
}
}

void get_flag(int x)
{
strcpy(s1,s);
int len=strlen(s);
s1[len]='#';
strrev(s);
strcat(s1+len+1,s);
get_Next(s1);
len=strlen(s1);
int k=Next[len-1];
while(k!=0)
{
flag[x][k-1]=1;
k=Next[k-1];
}
memset(s1,0,sizeof s1);
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
int Cas;
scanf("%d",&Cas);
while(Cas--)
{
for(int i=0;i<26;++i)
scanf("%d",&val[i]);
scanf("%s",s);
if(strlen(s)==1)
{
printf("%d\n",val[s[0]-'a']);continue;
}
get_sum();
memset(flag,0,sizeof flag);
get_flag(0);
get_flag(1);
int len=strlen(s);
reverse(flag[1],flag[1]+len);
long long ans=LLONG_MIN,tmp;
for(int i=0;i<len-1;++i)
{
tmp=0;
tmp=(flag[0][i]?sum[i]:0)+(flag[1][i+1]?sum[len-1]-sum[i]:0);
ans=ans>tmp?ans:tmp;
}
printf("%lld\n",ans);
}
return 0;
}
/*

*/


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: