扩展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.问 ...
随机推荐
- 面包板入门电子制作(class1)视频 全套30集高清
面包板入门电子制作(class1)套件(30集高清) 本套件以电子制作中最基础的元器件在面包板上搭建电路,用启发性的视频教学方式,使学习者熟悉电子电路基础.发挥想像力.在创新设计和制作中学会独立设计和 ...
- Xcode7 使用NSURLSession发送HTTP请求的问题
报错信息: Application Transport Security has blocked a cleartext HTTP (http://) resource load since it i ...
- Codeforces Round #160 (Div. 1) 题解【ABCD】
Codeforces Round #160 (Div. 1) A - Maxim and Discounts 题意 给你n个折扣,m个物品,每个折扣都可以使用无限次,每次你使用第i个折扣的时候,你必须 ...
- (原创)INTERVAL分区表与RANGE分区表相互转化
1.RANGE分区表转化为INTERVAL分区表 如果有MAXVALUE分区,则先删除,然后再用SET INTERVAL设置为自动分区间隔ALTER TABLE trdfat_profit DROP ...
- Android 5.0 Uicc框架分析
已同步更新至个人blog: dxjia.cn Uicc框架 UICC框架是Android在4.1引入的,使的对卡的管理控制更加清晰.要了解这个UICC框架,需要从UiccController开始, ...
- 关于Asp.Net MVC 中 UpdateModel 的未能更新***模型的 解决方案!
解决方案参考: http://blog.csdn.net/hudaijun/article/details/7293129 想法: 其实,不用UpdateModel,虽然笨些,但不会出什么古怪问题.当 ...
- 初探单点登录 SSO
单点登录 单点登录(Single sign-on,SSO)是一种访问控制,在多个软件应用中,用户只需登录其中一个应用,就可以成功访问其他应用:同样,用户只需注销其中一个应用,就可以成功注销其他应用. ...
- SAP-GR/IR的理解
SAP-GR/IR的理解 http://shousitukyou.blog.163.com/blog/static/13868005820109127046318/ GR/IR 1,采购的an i ...
- VC++ 学习笔记(序):神一样的语言
总的来说,我觉得VC++是一门神一样的语言——它是公认最强大.最复杂的:它一切以效率为第一要务,却又不肯落伍,拼命兼容现在的新的语言设计特点.本来在别的语言很容与就避开的问题,在这里要用很高的技巧去设 ...
- Android客户端与PHP服务端交互(一)---框架概述
背景 作为一个普通上班族,总是想做一些自认为有意义的事情,于是乎准备成立一个工作室,尽管目前正在筹备阶段,但是之前有些朋友提出一些需求的时候,我发现自己的能力还是有限,直到最近和一些技术牛朋友聊起这事 ...