题目链接: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. System.out.println()和System.out.write()的区别

    这两个函数一个是System.out.write()输出字符流,System.out.println()是输出字节流,很简单.看下面这个程序就明白了.     //import java.util.* ...

  2. [NOIP2011] 洛谷P1313 计算系数

    题目描述 给定一个多项式(by+ax)^k,请求出多项式展开后x^n*y^m 项的系数. 输入输出格式 输入格式: 输入文件名为factor.in. 共一行,包含5 个整数,分别为 a ,b ,k , ...

  3. 【ZOJ4053】Couleur(主席树,set,启发式)

    题意: 有n个位置,每个位置上的数字是a[i],现在有强制在线的若干个单点删除操作,每次删除的位置都不同,要求每次删除之后求出最大的连续区间逆序对个数 n<=1e5,1<=a[i]< ...

  4. POJ 1991 Turning in Homework(区间DP)

    题目链接 Turning in Homework 考虑区间DP $f[i][j][0]$为只考虑区间$[i, j]$且最后在$a[i]$位置交作业的答案. $f[i][j][1]$为只考虑区间$[i, ...

  5. 异常来自 HRESULT:0x800A01A8

    Windows 10 Enterprise Microsoft Office 2013 – Excel Oracle BI Publisher Desktop 11.1.1.7 异常来自 HRESUL ...

  6. BUPT复试专题—串查找(?)

    https://www.nowcoder.com/practice/a988eda518f242c29009f8620f654ede?tpId=67&tqId=29642&rp=0&a ...

  7. Python 一行命令ftp服务器

    Obligatory Twisted example: twistd -n ftp And probably useful: twistd ftp --help Usage: twistd [opti ...

  8. SolidEdge如何绘制变化半径倒圆角

    1 在要变化半径的边上打一些点   2 点击倒角命令的参数对话框,选择可变半径   3 选择倒角的直线,右击确认,再依次点击关键点,修改倒角数值,修改之后按回车,继续下一个点,直到结束.  

  9. C/C++知识要点2——STL中Vector、Map、Set容器的实现原理

    1.Vector是顺序容器.是一个动态数组.支持随机存取.插入.删除.查找等操作,在内存中是一块连续的空间.在原有空间不够情况下自己主动分配空间.添加为原来的两倍.vector随机存取效率高,可是在v ...

  10. ProFTPD配置匿名登录与文件夹訪问权限控制

    对ProFTPDserver配置匿名登录.         查看配置文件proftpd.conf.默认情况下配置文件里的.匿名登录配置User和Group均为ftp. 查看/etc/passwd确认用 ...