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的更多相关文章

  1. HDU 3613 Best Reward 正反两次扩展KMP

    题目来源:HDU 3613 Best Reward 题意:每一个字母相应一个权值 将给你的字符串分成两部分 假设一部分是回文 这部分的值就是每一个字母的权值之和 求一种分法使得2部分的和最大 思路:考 ...

  2. HDU 3613 Best Reward(扩展KMP求前后缀回文串)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3613 题目大意: 大意就是将字符串s分成两部分子串,若子串是回文串则需计算价值,否则价值为0,求分割 ...

  3. HDU - 3613 Best Reward(manacher或拓展kmp)

    传送门:HDU - 3613 题意:给出26个字母的价值,然后给你一个字符串,把它分成两个字符串,字符串是回文串才算价值,求价值最大是多少. 题解:这个题可以用马拉车,也可以用拓展kmp. ①Mana ...

  4. hdu 3613"Best Reward"(Manacher算法)

    传送门 题意: 国王为了犒劳立下战功的大将军Li,决定奖给Li一串项链,这个项链一共包含26中珠子"a~z",每种珠子都有 相应的价值(-100~100),当某个项链可以构成回文时 ...

  5. 扩展KMP - HDU 4333 Revolving Digits

    Revolving Digits Problem's Link Mean: 给你一个字符串,你可以将该字符串的任意长度后缀截取下来然后接到最前面,让你统计所有新串中有多少种字典序小于.等于.大于原串. ...

  6. HDU 3613 Best Reward(扩展KMP)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=3613 [题目大意] 一个字符串的价值定义为,当它是一个回文串的时候,价值为每个字符的价值的和,如果 ...

  7. HDU 3613 Best Reward(拓展KMP算法求解)

    题目链接: https://cn.vjudge.net/problem/HDU-3613 After an uphill battle, General Li won a great victory. ...

  8. HDU 3613 Best Reward(KMP算法求解一个串的前、后缀回文串标记数组)

    题目链接: https://cn.vjudge.net/problem/HDU-3613 After an uphill battle, General Li won a great victory. ...

  9. HDU 3613 Best Reward ( 拓展KMP求回文串 || Manacher )

    题意 : 给个字符串S,要把S分成两段T1,T2,每个字母都有一个对应的价值,如果T1,T2是回文串,那么他们就会有一个价值,这个价值是这个串的所有字母价值之和,如果不是回文串,那么这串价值就为0.问 ...

随机推荐

  1. 使用PopupWindow实现Menu功能

    参考:http://www.cnblogs.com/sw926/p/3230659.html 注意: PopupWindow会给PopupView设置Padding,会导致ContentView的左右 ...

  2. html5开发之viewport使用

    随着高端手机(Andriod,Iphone,Ipod,WinPhone等)的盛行,移动互联应用开发也越来越受到人们的重视,用html5开发移动应用是最好的选择.然而,每一款手机有不同的分辨率,不同屏幕 ...

  3. 使用Aspose.Cells 根据模板生成excel里面的 line chart

    目的: 1.根据模板里面的excel数据信息,动态创建line chart 2.linechart 的样式改为灰色 3.以流的形式写到客户端,不管客户端是否装excel,都可以导出到到客户端 4.使用 ...

  4. C# barcode生成代码

    protected void Page_Load(object sender, EventArgs e) { string code = Request.Params["code" ...

  5. 【转】--在Android源码树中添加userspace I2C读写工具(i2c-util)

    通过/dev/i2c-n节点,用户可以在userspace直接访问板上的i2c外设寄存器,主要是透过I2C_RDWR这个IO控制命令将i2c_msg数组传递给kernel去执行.下面的代码可以完成这个 ...

  6. ubuntu系统从中文环境改成英文环境

      我们在 安装ubuntu server版的时候,有人可能选择了中文环境安装,因为那样好设置时区等参数,可是安装好了后,运行某些命令的时候会有中文乱码提示,看起很是头蛋疼, 我们就需要将其改成英文环 ...

  7. Mobilize.Net Silverlight bridge to Windows 10 UWP

    Windows UWP 既 Windows 10 Universal Windows platform,这个微软基于Windows NT内核的个运行时(Runtime)平台,此平台横跨所有的 Wind ...

  8. Unity3d游戏中自定义贝塞尔曲线编辑器[转]

    关于贝塞尔曲线曲线我们再前面的文章提到过<Unity 教程之-在Unity3d中使用贝塞尔曲线>,那么本篇文章我们来深入学习下,并自定义实现贝塞尔曲线编辑器,贝塞尔曲线是最基本的曲线,一般 ...

  9. 向上下左右不间断无缝滚动图片的效果(兼容火狐和IE)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. POJ 2078 Matrix

    Matrix Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 3239   Accepted: 1680 Descriptio ...