题目链接:https://vjudge.net/problem/HDU-3613

Best Reward

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 3104    Accepted Submission(s): 1277

Problem Description
After an uphill battle, General Li won a great victory. Now the head of state decide to reward him with honor and treasures for his great exploit.

One of these treasures is a necklace made up of 26 different kinds of gemstones, and the length of the necklace is n. (That is to say: n gemstones are stringed together to constitute this necklace, and each of these gemstones belongs to only one of the 26 kinds.)

In accordance with the classical view, a necklace is valuable if and only if it is a palindrome - the necklace looks the same in either direction. However, the necklace we mentioned above may not a palindrome at the beginning. So the head of state decide to cut the necklace into two part, and then give both of them to General Li.

All gemstones of the same kind has the same value (may be positive or negative because of their quality - some kinds are beautiful while some others may looks just like normal stones). A necklace that is palindrom has value equal to the sum of its gemstones' value. while a necklace that is not palindrom has value zero.

Now the problem is: how to cut the given necklace so that the sum of the two necklaces's value is greatest. Output this value.

 
Input
The first line of input is a single integer T (1 ≤ T ≤ 10) - the number of test cases. The description of these test cases follows.

For each test case, the first line is 26 integers: v1, v2, ..., v26 (-100 ≤ vi ≤ 100, 1 ≤ i ≤ 26), represent the value of gemstones of each kind.

The second line of each test case is a string made up of charactor 'a' to 'z'. representing the necklace. Different charactor representing different kinds of gemstones, and the value of 'a' is v1, the value of 'b' is v2, ..., and so on. The length of the string is no more than 500000.

 
Output
Output a single Integer: the maximum value General Li can get from the necklace.
 
Sample Input
2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
aba
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
acacac
 
Sample Output
1
6
 
Source
 
Recommend
lcy

题解:

1.求出字符串值的前缀和以及后缀和。

2.用Manacher算法或者扩展KMP算法求出:每个前缀和每个后缀是否为回文串。

3.枚举分分割位置,然后再根据左右段字符串是否为回文串来进行求值。

4.Manacher算法的认识在处理的时候,如果以“#”为中点,那么实际的回文串长度为偶数;如果以输入的字符为中点,那么实际的回文串长度为奇数。

Manacher:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <sstream>
#include <algorithm>
using namespace std;
typedef long long LL;
const double eps = 1e-;
const int INF = 2e9;
const LL LNF = 9e18;
const int MAXN = 5e5+; char s[MAXN];
int val[], pre[MAXN], suf[MAXN];
int sum[MAXN][]; int Ma[MAXN<<], Mp[MAXN<<];
void Manacher(char *s, int len)
{
int l = ;
Ma[l++] = '$'; Ma[l++] = '#';
for(int i = ; i<len; i++)
{
Ma[l++] = s[i];
Ma[l++] = '#';
}
Ma[l] = ; int mx = , id = ;
for(int i = ; i<l; i++)
{
Mp[i] = mx>=i?min(Mp[*id-i], mx-i):;
while(Ma[i-Mp[i]-]==Ma[i+Mp[i]+]) Mp[i]++;
if(i+Mp[i]>mx)
{
mx = i+Mp[i];
id = i;
} //记录以s[i/2-1]为中点(长度为奇时,为中点;长度为偶时,为左半段的末点)时的最长回文串
//如果处理的时候,以“#”为中点,那么实际的长度为偶数
//如果处理的时候,以输入的字符为中点,那么实际的长度为奇数
if(i>=) sum[i/-][Ma[i]!='#'] = Mp[i];
}
} int main()
{
int T;
scanf("%d", &T);
while(T--)
{
for(int i = ; i<; i++)
scanf("%d", &val[i]); scanf("%s", s);
int len = strlen(s);
pre[] = val[s[]-'a'];
suf[len-] = val[s[len-]-'a'];
for(int i = ; i<len; i++)
{
pre[i] = pre[i-] + val[s[i]-'a']; //求前缀和
suf[len-i-] = suf[len-i] + val[s[len-i-]-'a']; //求后缀和
} memset(sum, , sizeof(sum));
Manacher(s, len); int ans = -INF;
for(int i = ; i<=len-; i++)
{
int Lmid = i/, Rmid = (i++len-)/; //找到左右两段的中点
int Llen = i+, Rlen = len-Llen; //求出左右两段的长度 int tmp = ;
if(sum[Lmid][Llen%]==Llen) tmp += pre[i]; //如果左段为回文串
if(sum[Rmid][Rlen%]==Rlen) tmp += suf[i+]; //如果右段为回文串
ans = max(ans, tmp);
}
printf("%d\n", ans);
}
}

扩展KMP:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <sstream>
#include <algorithm>
using namespace std;
typedef long long LL;
const double EPS = 1e-;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 5e5+; void pre_EXKMP(char x[], int m, int Next[])
{
Next[] = m;
int j = ;
while(j+<m && x[+j]==x[+j]) j++;
Next[] = j;
int k = ;
for(int i = ; i<m; i++)
{
int p = Next[k]+k-;
int L = Next[i-k];
if(i+L<=p) Next[i] = L; else
{
j = max(, p-i+);
while(i+j<m && x[i+j]==x[+j]) j++;
Next[i] = j;
k = i;
}
}
} //next[i]: x[i...m-1] 与 x[0...m-1]的最长公共前缀
//exd[i]: y[i...n-1] 与 x[0...m-1]的最长公共前缀
void EXKMP(char x[], int m, char y[], int n, int Next[], int exd[])
{
pre_EXKMP(x,m,Next); //获取x的next数组(x与自己的匹配)
int j = ;
while(j<n && j<m && x[j]==y[j]) j++;
exd[] = j;
int k = ; //k使得k+exd[k]-1最大,即匹配得最远的y后缀
for(int i = ; i<n; i++)
{
int p = exd[k]+k-; //p为y字符串匹配得最远的位置
int L = Next[i-k]; //因为y[k...k+exd[k]-1] == x[0...exd[k]-1]
//所以y[i...k+exd[k]-1] == x[i-k...exd[k]-1]
//我们已知: x[i-k...] 与 x[0...]的最长公共前缀为next[i-k]
//那么我们可以利用next[i-k]的到:y[i...] 与 x[0...]至少匹配了多少个字符
//然后i+next[i-k]就是以i为起始,目前为止匹配得最远的地方。
//如果i+next[i-k]<=p,即小于等于之前匹配最远的,那么exd[i]就等于i+next[i-k]
//否则,之后的字符不能确定是否匹配,所以要继续匹配下去,然后设置k为i
if(i+L<=p) exd[i] = L;
else
{
j = max(,p-i+); //p-i+1即通过next[i-k]得知的y[i...]与x[0...]至少匹配的字符个数
while(i+j<n && j<m && y[i+j]==x[+j]) j++;
exd[i] = j;
k = i;
}
}
} char s1[MAXN], s2[MAXN];
int val[], Next[MAXN], exd1[MAXN], exd2[MAXN], sum[MAXN]; int main()
{
int T;
scanf("%d",&T);
while(T--)
{
for(int i = ; i<; i++)
scanf("%d",&val[i]);
scanf("%s",s1); int len = strlen(s1);
sum[] = val[s1[]-'a'];
for(int i = ; i<len; i++)
sum[i] = sum[i-] + val[s1[i]-'a']; memcpy(s2, s1, sizeof(s2)); //复制并反转
reverse(s2, s2+len); EXKMP(s1, len, s2, len, Next, exd1); //前缀
EXKMP(s2, len, s1, len, Next, exd2); //后缀
int ans = ;
reverse(exd1, exd1+len); //这样exd1就是前缀, exd2就是后缀了。
for(int i = ; i<len-; i++)
{
int tmp = ;
if(exd1[i]==i+) tmp += sum[i];
if(exd2[i+]==len-(i+)) tmp += sum[len-]-sum[i];
ans = max(ans,tmp);
}
printf("%d\n", ans);
}
}

HDU3613 Best Reward —— Manacher算法 / 扩展KMP + 枚举的更多相关文章

  1. manacher 和 扩展KMP

    manacher 和 扩展KMP 事实上,这两个东西是一样的. 考虑 manacher 的过程 我们实时维护最远扩展的位置 \(mx\) 以及这个回文串的回文中心 \(l\) ,那么显然当然位置如果没 ...

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

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

  3. hdu3613 Best Reward manacher+贪心+前缀和

    After an uphill battle, General Li won a great victory. Now the head of state decide to reward him w ...

  4. hdu3613 Best Reward 扩展kmp or O(n)求最大回文子串

    /** 题目:hdu3613 Best Reward 链接:http://acm.hdu.edu.cn/showproblem.php?pid=3613 题意:有一个字符串,把他切成两部分. 如果这部 ...

  5. KMP 、扩展KMP、Manacher算法 总结

    一. KMP 1 找字符串x是否存在于y串中,或者存在了几次 HDU1711 Number Sequence HDU1686 Oulipo HDU2087 剪花布条 2.求多个字符串的最长公共子串 P ...

  6. 浅谈Manacher算法与扩展KMP之间的联系

    首先,在谈到Manacher算法之前,我们先来看一个小问题:给定一个字符串S,求该字符串的最长回文子串的长度.对于该问题的求解.网上解法颇多.时间复杂度也不尽同样,这里列述几种常见的解法. 解法一   ...

  7. [扩展KMP][HDU3613][Best Reward]

    题意: 将一段字符串 分割成两个串 如果分割后的串为回文串,则该串的价值为所有字符的权值之和(字符的权值可能为负数),否则为0. 问如何分割,使得两个串权值之和最大 思路: 首先了解扩展kmp 扩展K ...

  8. ACM之路(12)—— KMP & 扩展KMP & Manacher

    最近做完了kuangbin的一套关于kmp的题目(除了一道字典树的不会,因为还没学字典树所以先放放),做个总结.(kuangbin题目的链接:http://acm.hust.edu.cn/vjudge ...

  9. KMP && Manacher && 扩展KMP整理

    KMP算法: kmp示例代码: void cal_next(char *str, int *next, int len) { next[0] = -1;//next[0]初始化为-1,-1表示不存在相 ...

随机推荐

  1. cf711E ZS and The Birthday Paradox

    ZS the Coder has recently found an interesting concept called the Birthday Paradox. It states that g ...

  2. cf287D Shifting

    John Doe has found the beautiful permutation formula. Let's take permutation p = p1, p2, ..., pn. Le ...

  3. Mysql安装及自动化部署脚本方案

    一.简介 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库, 每个数据库都有一个或多个不同的API用于创建,访问,管理,搜索和复制所保存的数据. 我们也可以将数据存储在文件中,但是 ...

  4. MongoDB存储引擎(上)——MMAPv1

    3.0版本以前,MongoDB只有一个存储引擎——MMAP,MongoDB3.0引进了一个新的存储引擎——WiredTiger,同时对原有的MMAP引擎进行改进,产生MMAPv1存储引擎,并将其设置为 ...

  5. git(一):了解、学习、安装git

    自述 一直到今天才真正的去了解学习使用git,看<git权威指南>这本书的第一篇,忽然有很多共鸣,比如在大学开始编程的时候,总是把写的所有demo和项目保存在U盘里,内存不够用就改为移动硬 ...

  6. Leetcode 数组问题:删除排序数组内的重复项

    问题描述: 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成 ...

  7. JStorm学习

    一.简介 JStorm是一个分布式实时计算引擎.JStorm是一个类似于Hadoop MapReduce的系统,用户按照指定的接口实现一个任务,然后将这个任务交给JStorm系统,JStorm将这个任 ...

  8. 2716 [Violet 3] 天使玩偶

    @(BZOJ)[CDQ分治] Sample Input 100 100 81 23 27 16 52 58 44 24 25 95 34 2 96 25 8 14 97 50 97 18 64 3 4 ...

  9. FIREDAC字段类型映射

    为什么需要字段类型映射? 作为通用型数据引擎的FIREDAC或者UNIDAC,驱动某一种数据库以后,总有一些数据库的一些字段类型,数据引擎不能识别,反应到程序中就是数据引擎不能正确地读取该字段的值 . ...

  10. Java中的Copy-on-Write容器 & ConcurrentHashMap & HashTable比较

    参考这篇文章:Link 从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet ...