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. JMeter教程01-下载和安装

    下载JMeter http://jmeter.apache.org/download_jmeter.cgi 以上是下载地址 更多课程 访问www.bamn.cn 北盟网校 下载后解压 apache-j ...

  2. [GraphQL] Use GraphQL's List Type for Collections

    In order to handle collections of items in a GraphQL Schema, GraphQL has a List Type. In this video, ...

  3. chm格式文件能打开,但看不到内容问题

    是chm格式的能打开文件,也能看到左边的目录信息,但是无法显示右面的具体内容.报错:无法显示网页.错误页面的url是:res://C:WINDOWSsystem32shdoclc.dll/dnserr ...

  4. 从一个例子看现代C++的威力

    引子 最近准备重构一下我的kapok库,让meta函数可以返回元素为kv的tuple,例如: struct person { std::string name; int age; META(name, ...

  5. LoadRunner性能测试结果分析

    LoadRunner性能测试结果分析http://www.docin.com/p-793607435.html

  6. Windows Store 开发总结——文件操作

    1.读取Isolated Storage 每个Metro程序都有三个文件夹:Local,Roaming,Temp.每个文件夹的访问方法都是相同的. Local用于将数据存储在本地,这是程序特定的文件夹 ...

  7. [转帖]HOWTO rename column name in Sqlite3 database

    原文在此 Say you have a table and need to rename "colb" to "col_b": First you rename ...

  8. ODAC (V9.5.15) 学习笔记(二十)大数据量获取处理

    ODAC获取数据的效率比较高,在Web程序中希望能够更快获取第一页的数据时,可以有几种方式: 1.在数据库中进行分页处理: 2.获取所有数据,只是快速返回第一页数据. 第一种方案对应用服务器资源消耗最 ...

  9. ubuntu14.04 LTS 更新源

    官方源: deb http://archive.ubuntu.com/ubuntu/ trusty main restricted universe multiverse deb http://arc ...

  10. MySQL数据库之数据类型BOOL/BOOLEAN与TINYINT测试总结

    From: http://database.51cto.com/art/201203/323863.htm 网络上很多人咨询mysql是否提供布尔类型?MySQL数据库确实提供布尔类型,此数据类型的关 ...