扩展KMP --- HDU 3613 Best Reward
Best Reward
Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=3613
Mean:
给你一个字符串,每个字符都有一个权值(可能为负),你需要将这个字符串分成两个子串,使得这两个子串的价值之和最大。一个子串价值的计算方法:如果这个子串是回文串,那么价值就是这个子串所有字符权值之和;否则价值为0。
analyse:
扩展KMP算法运用。
总体思路:
找出所有包含第一个字母的回文串和包含最后一个字母的回文串,然后O(n)扫一遍,每次判断第i个字母之前(包含第i个字母)的子串是否是回文,以及从第i个字母后的子串是否是回文,然后计算出答案,取最大值。
具体做法:
假设输入的字符串是"abcda"
构造串s1="abcda#adcba"
求s1的Next数组,得到了包含第一个字母的回文串的位置;
构造串s2="adcba#abcda"
求s2的Next数组,得到了包含最后一个字母的回文串的位置;
用两个flag数组标记这些位置,然后扫一遍就得答案了。
中间加一个'#'并后接反串的目的是:当整个串都是回文的时候能够被Next数组记录下。
Time complexity: O(nlogn)
Source code:
第一遍写,不够优化:
/*
* this code is made by crazyacking
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <string>
#include <stack>
#include <cmath>
#include <set>
#include <map>
#include <cstdlib>
#include <climits>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cstring>
#define MAXN 500010*2
#define LL long long
using namespace std;
int len;
int Next[MAXN],ne[MAXN];
int sum[MAXN];
vector<int> val;
bool flag1[MAXN],flag2[MAXN];
char s[MAXN],s1[MAXN],s2[MAXN],sr[MAXN];
void get_sum()
{
sum[]=val[s[]-'a'];
for(int i=;i<len;++i)
sum[i]=sum[i-]+val[s[i]-'a'];
}
void get_s1()
{
strcpy(s1,s);
s1[len]='#';
s1[len+]='\0';
strcat(s1,sr);
}
void get_s2()
{
strcpy(s2,sr);
s2[len]='#';
s2[len+]='\0';
strcat(s2,s);
} void get_Next(char s[])
{
Next[]=;
int s_len=strlen(s);
for(int i=,k=;i<s_len;++i)
{
while(k!= && s[i]!=s[k])
k=Next[k-];
if(s[i]==s[k]) k++;
Next[i]=k;
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie();
int Cas;
cin>>Cas;
while(Cas--)
{
val.clear();
int cnt=,t;
while(cnt--)
{
cin>>t,val.push_back(t);
}
scanf("%s",s);
len=strlen(s);
if(strlen(s)==)
{
printf("%d\n",val[s[]-'a']);continue;
}
get_sum();
strcpy(sr,s);
strrev(sr);
get_s1();
get_s2();
memset(flag1,,sizeof flag1);
memset(flag2,,sizeof flag2);
get_Next(s1);
int k=Next[*len];
while(k!=)
{
flag1[k-]=;
k=Next[k-];
}
get_Next(s2);
k=Next[*len];
while(k!=)
{
flag2[k-]=;
k=Next[k-];
}
reverse(flag2,flag2+len);
long long ans=INT_MIN;
long long tmp=;
for(int i=;i<len-;++i)
{
tmp=;
if(flag1[i])
{
tmp+=sum[i];
}
if(flag2[i+])
{
tmp=tmp+(sum[len-]-sum[i]);
}
if(tmp>ans)
ans=tmp; }
cout<<ans<<endl; }
return ;
}
/* */
优化后的代码:
/*
* 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=;
int val[],Next[MAXN*],sum[MAXN];
char s[MAXN],s1[MAXN*];
bool flag[][MAXN];
void get_sum()
{
int len=strlen(s);
sum[]=val[s[]-'a'];
for(int i=;i<len;++i)
sum[i]=sum[i-]+val[s[i]-'a'];
} void get_Next(char ss[])
{
int len=strlen(ss);
Next[]=;
int k=;
for(int i=;i<len;++i)
{
while(k!= && ss[i]!=ss[k])
k=Next[k-];
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+,s);
get_Next(s1);
len=strlen(s1);
int k=Next[len-];
while(k!=)
{
flag[x][k-]=;
k=Next[k-];
}
memset(s1,,sizeof s1);
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie();
int Cas;
scanf("%d",&Cas);
while(Cas--)
{
for(int i=;i<;++i)
scanf("%d",&val[i]);
scanf("%s",s);
if(strlen(s)==)
{
printf("%d\n",val[s[]-'a']);continue;
}
get_sum();
memset(flag,,sizeof flag);
get_flag();
get_flag();
int len=strlen(s);
reverse(flag[],flag[]+len);
long long ans=LLONG_MIN,tmp;
for(int i=;i<len-;++i)
{
tmp=;
tmp=(flag[][i]?sum[i]:)+(flag[][i+]?sum[len-]-sum[i]:);
ans=ans>tmp?ans:tmp;
}
printf("%lld\n",ans);
}
return ;
}
/* */
扩展KMP --- HDU 3613 Best Reward的更多相关文章
- HDU 3613 Best Reward 正反两次扩展KMP
题目来源:HDU 3613 Best Reward 题意:每一个字母相应一个权值 将给你的字符串分成两部分 假设一部分是回文 这部分的值就是每一个字母的权值之和 求一种分法使得2部分的和最大 思路:考 ...
- HDU 3613 Best Reward(扩展KMP求前后缀回文串)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3613 题目大意: 大意就是将字符串s分成两部分子串,若子串是回文串则需计算价值,否则价值为0,求分割 ...
- HDU - 3613 Best Reward(manacher或拓展kmp)
传送门:HDU - 3613 题意:给出26个字母的价值,然后给你一个字符串,把它分成两个字符串,字符串是回文串才算价值,求价值最大是多少. 题解:这个题可以用马拉车,也可以用拓展kmp. ①Mana ...
- hdu 3613"Best Reward"(Manacher算法)
传送门 题意: 国王为了犒劳立下战功的大将军Li,决定奖给Li一串项链,这个项链一共包含26中珠子"a~z",每种珠子都有 相应的价值(-100~100),当某个项链可以构成回文时 ...
- 扩展KMP - HDU 4333 Revolving Digits
Revolving Digits Problem's Link Mean: 给你一个字符串,你可以将该字符串的任意长度后缀截取下来然后接到最前面,让你统计所有新串中有多少种字典序小于.等于.大于原串. ...
- HDU 3613 Best Reward(扩展KMP)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=3613 [题目大意] 一个字符串的价值定义为,当它是一个回文串的时候,价值为每个字符的价值的和,如果 ...
- HDU 3613 Best Reward(拓展KMP算法求解)
题目链接: https://cn.vjudge.net/problem/HDU-3613 After an uphill battle, General Li won a great victory. ...
- HDU 3613 Best Reward(KMP算法求解一个串的前、后缀回文串标记数组)
题目链接: https://cn.vjudge.net/problem/HDU-3613 After an uphill battle, General Li won a great victory. ...
- HDU 3613 Best Reward ( 拓展KMP求回文串 || Manacher )
题意 : 给个字符串S,要把S分成两段T1,T2,每个字母都有一个对应的价值,如果T1,T2是回文串,那么他们就会有一个价值,这个价值是这个串的所有字母价值之和,如果不是回文串,那么这串价值就为0.问 ...
随机推荐
- [AYUI]QQ管家源码已经开源
(0-50元 黑色字体 享受AY 1周的 ayui 技术问答) (50-100元 绿色字体 享受AY 15天的 ayui 技术问答) (100-150元 蓝色字体 享受AY 20天的 ayui ...
- std::bind和std::function
std::bind 用于绑定一个函数,返回另外一种调用方式的函数对象 ,可以改变参数顺序 和个数,特别是在多线程的程序中,经常用它将函数进行包装,然后打包发送给工作线程,让工作线程去执行我们的任务. ...
- leveldb - log格式
log文件在LevelDb中的主要作用是系统故障恢复时,能够保证不会丢失数据.因为在将记录写入内存的Memtable之前,会先写入Log文件,这样即使系统发生故障,Memtable中的数据没有来得及D ...
- UICollectionView瀑布流的实现原理(转)
http://ios.jobbole.com/85689/ 和使用 UIScollView 创刊一个瀑布流是一样的方式 7cc829d3gw1f4nq2oc09zj20j00hvq90.jpg 我的 ...
- 在c#程式中配置log4net
參考網址: http://www.cnblogs.com/kissazi2/p/3393595.html http://www.cnblogs.com/kissazi2/p/3389551.html ...
- 【NLP】word2vec
http://blog.csdn.net/mytestmy/article/details/26969149?utm_source=tuicool&utm_medium=referral
- Web GIS 离线地图
Web GIS 离线地图 1,基于瓦片的离线地图下载 博客园 阿凡卢 提供了离线地图的下载工具,下载地址:http://pan.baidu.com/s/1hqvQr7e 具体使用见 参考资料2 阿凡卢 ...
- [英] 推荐 15 个 jQuery 选择框插件
jQuery Selectbox Plugins let you create beautiful and eye catching select box for your websites inst ...
- MMO之禅(三)职业能力
MMO之禅(三)职业能力 --技术九层阶梯 Zephyr 201304 有了精神,我们还需要实际的行动. 到底需要什么能力?自我分析,窃以为为有九层,无所谓高低,因为每一层都需要不断地砥砺,编程,本身 ...
- 【译文】 C#面向对象的基本概念 (Basic C# OOP Concept) 第一部分(类,对象,变量,方法,访问修饰符)
译文出处:http://www.codeproject.com/Articles/838365/Basic-Csharp-OOP-Concept 相关文档:http://files.cnblogs.c ...