/**
题目:hdu3613 Best Reward
链接:http://acm.hdu.edu.cn/showproblem.php?pid=3613
题意:有一个字符串,把他切成两部分。
如果这部分是回文串,那么他的值为所有字母的权值和。否则这部分值为0;这两部分的值和为该切法的权值。
求最大的切法的权值。
思路:
如果能够判断[0,i],[i,n-1]是一个回文串(0<=i<n)那么就可以枚举i,计算切割位置为i时候两部分的贡献和。
取最大的。
利用O(n)的算法求最长回文子串的做法获得f[i];表示以第i个字符为中心的最长回文子串的长度;
就可以获得l[i],r[i];
l[i]=1表示[0,i]是一个回文串.r[i]=1表示[i,n-1]是一个回文串。 */
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<set>
#include <iostream>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6+;///给定的长度
char s[maxn*], t[maxn];///要乘以2,因为构造了'*'
int f[maxn*];///令f[i] 表示以第i个字符为中心的最长回文子串的长度
int sum[maxn*], w[];
int l[maxn*], r[maxn*];///l[i]=1表示[0,i]是一个回文串.r[i]=1表示[i,n-1]是一个回文串。
int longest(char *a)///最长回文子串
{
int z = ;
for(int i = ; a[i]!='\0'; i++){
s[z++] = a[i];
s[z++] = '*';
}
z--;
s[z] = '\0';
int j = ;
int ans = ;
f[] = ;
for(int i = ; i < z; i++){
if(f[j]-*(i-j)<=) {
f[i] = ;
}else{
f[i] = min(f[*j-i],f[j]-*(i-j));
}
int l = i-f[i]/-, r = i+f[i]/+;
while(l>=&&r<z&&s[l]==s[r]){
l--, r++;
f[i]+=;
}
if(f[i]/+i>f[j]/+j){
j = i;
}
if(f[i]>ans){
ans = f[i];
}
}
int mas = ;
for(int i = ; i < z; i++){
if(f[i]==ans){
int l = i-f[i]/, r = i+f[i]/;
int cnt;
if(s[l]=='*'){
cnt = f[i]/;
}else cnt = f[i]/+;
mas = max(mas,cnt);
}
}
return mas;
}
int main()
{
//freopen("in.txt","r",stdin);
int T;
int cas = ;
cin>>T;
while(T--){
for(int i = ; i < ; i++) scanf("%d",&w[i]);
scanf("%s",t);
longest(t);
int n = strlen(s);
sum[] = w[s[]-'a'];
for(int i = ; i < n; i++){
if(s[i]=='*') sum[i] = sum[i-]+;
else sum[i] = sum[i-]+w[s[i]-'a'];
}
memset(l, , sizeof l);
memset(r, , sizeof r);
for(int i = ; i < n; i++){
int L = i-(f[i]-)/;
int R = i+(f[i]-)/;
if(L==){
l[R] = ;
}
if(R==n-){
r[L] = ;
}
}
int ans = -INF, ansa, ansb;
for(int i = ; i < n-; i++){
if(i%){
if(l[i-]){
ansa = sum[i-];
}else ansa = ;
if(r[i+]){
ansb = sum[n-]-sum[i-];
}else ansb = ;
}else
{
if(l[i-]){
ansa = sum[i-];
}else ansa = ;
if(r[i]){
ansb = sum[n-]-sum[i-];
}else ansb = ;
} ans = max(ans,ansa+ansb);
}
printf("%d\n",ans);
}
return ;
}
/**
题目:hdu3613 Best Reward
链接:http://acm.hdu.edu.cn/showproblem.php?pid=3613
题意:有一个字符串,把他切成两部分。
如果这部分是回文串,那么他的值为所有字母的权值和。否则这部分值为0;这两部分的值和为该切法的权值。
求最大的切法的权值。
思路:
如果能够判断[0,i],[i,n-1]是一个回文串(0<=i<n)那么就可以枚举i,计算切割位置为i时候两部分的贡献和。
取最大的。 扩展kmp的做法。
先计算l[i]=1,表示[0,i]是一个回文串;那么[0,k1]与[k2,i]相等。0是固定的。
获得原串t的反转串s。求extend[i],表示s串从[i,n-1]与原串t的最长公共前缀。
枚举s串的i。那么从[i,n-1]的长度n-i;如果extend[i]*2+1>=n-i那么表示原串t中的[0,n-1-i]是一个回文串即l[n-1-i] = 1; 现在求r[i]=1,表示[i,n-1]是一个回文串;那么[i,k1]与[k2,n-1]相等。n-1是固定的。
求extend[i],表示t串从[i,n-1]与s串的最长公共前缀。
枚举t串的i。那么从[i,n-1]的长度为n-i;如果extend[i]*2+1>=n-i那么表示原串[i,n-1]是一个回文串即r[i] = 1; */
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <iostream>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 5e5+;
char s[maxn], t[maxn];
int f[maxn], Next[maxn], extend[maxn];
int sum[maxn], w[];
int l[maxn], r[maxn];///l[i]=1表示[0,i]是一个回文串.r[i]=1表示[i,n-1]是一个回文串。
void GetNext(char *T,int* next)
{
int a=;
int Tlen=strlen(T);
next[]=Tlen;
while(a<Tlen-&&T[a]==T[a+]) a++;
next[]=a;
a=;
for(int k=;k<Tlen;k++)
{
int p=a+next[a]-,L=next[k-a];
if((k-)+L>=p)
{
int j=(p-k+)>? p-k+:;
while(k+j<Tlen&&T[k+j]==T[j]) j++;
next[k]=j;
a=k;
}
else next[k]=L;
}
} void GetExtend(char *S,char *T,int* next,int* extend)
{
int a=;
GetNext(T,next);
int Slen=strlen(S);
int Tlen=strlen(T);
int MinLen=Slen<Tlen? Slen:Tlen;
while(a<MinLen&&S[a]==T[a]) a++;
extend[]=a;
a=;
for(int k=;k<Slen;k++)
{
int p=a+extend[a]-,L=next[k-a];
if((k-)+L>=p)
{
int j=(p-k+)>? p-k+:;
while(k+j<Slen&&j<Tlen&&S[k+j]==T[j]) j++;
extend[k]=j;
a=k;
}
else extend[k]=L;
}
}
void getlr(int* extend,int *l,int flag,int n)
{
int len;
for(int i = ; i < n; i++){
len = n-i;
if(extend[i]*+>=len){
if(flag) l[i] = ;
else l[n--i] = ;
}
}
}
void test(int *f,int n)
{
for(int i = ; i < n; i++){
printf("f[%d] = %d\n",i,f[i]);
}
}
int main()
{
//freopen("in.txt","r",stdin);
int T;
cin>>T;
while(T--){
for(int i = ; i < ; i++) scanf("%d",&w[i]);
scanf("%s",t);
int n = strlen(t);
for(int i = ; i < n; i++) s[n--i] = t[i];
s[n] = '\0';
sum[] = w[t[]-'a'];
for(int i = ; i < n; i++){
sum[i] = sum[i-]+w[t[i]-'a'];
}
memset(l, , sizeof l);
memset(r, , sizeof r); GetExtend(s,t,Next,extend);
getlr(extend,l,,n); GetExtend(t,s,Next,extend);
getlr(extend,r,,n); int ans = -INF, ansa, ansb;
for(int i = ; i < n; i++){
if(l[i-]){
ansa = sum[i-];
}else ansa = ;
if(r[i]){
ansb = sum[n-]-sum[i-];
}else ansb = ;
ans = max(ans,ansa+ansb);
}
printf("%d\n",ans);
}
return ;
}

hdu3613 Best Reward 扩展kmp or O(n)求最大回文子串的更多相关文章

  1. [LeetCode] 647. 回文子串 ☆☆☆(最长子串、动态规划、中心扩展算法)

    描述 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串. 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串. 示例 1: 输入: "abc" ...

  2. 【LeetCode】最长回文子串【动态规划或中心扩展】

    给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: "babad"输出: "bab"注意: " ...

  3. S - Best Reward 扩展KMP

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

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

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

  5. Best Reward HDU 3613(回文子串Manacher)

    题目大意:有一个串(全部由小写字母组成),现在要把它分成两部分,如果分开后的部分是回文串就计算出来它的价值总和,如果不是回文的那么价值就是0,最多能得到的最大价值.   分析:首先的明白这个最大价值有 ...

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

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

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

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

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

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

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

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

随机推荐

  1. eslint 错误

    是因为你使用了eslint,这个是eslint的规范报错,能不用分号就不用分号. 去掉封号就醒了. 另外,方法的()前面也要有空格,不然页报错: indentifier is not in a cam ...

  2. 使用airdrop进行文件共享

    使用airdrop进行文件共享 学习了: https://support.apple.com/zh-cn/HT203106 https://zh.wikihow.com/%E5%9C%A8Mac%E4 ...

  3. [Android] Android工程以jar包形式向第三方应用提供服务

    参考: http://www.cnblogs.com/0616--ataozhijia/p/4094952.html 以API 19为例: 系统默认提供的 android.jar整体大小为: 21.8 ...

  4. Linux 搭建svn环境

    第一步:下载并安装svn sudo apt-get install subversion 第二步:创建版本库目录(此仅为目录,为后面创建版本库提供存放位置) 选择在var路径下创建版本库,当前处于根目 ...

  5. 安卓新闻client笔记积累

    做一个项目,假设有第三方的框架的话.就会简单非常多.如今看的这个新闻client就用到了很多框架,还有非常多知识点,放在这里,记录下来. (1)Android Volley 之自己定义Request ...

  6. 【大盛】全网首发HTC One/M7 最新本地化TrickDroid9.0/固件升级/永久root/高级,快速设置/稳定,流畅经典ROM

    了解更多请关注:点击打开链接 ROM版本 HTC One/M7_TrickDroid9.0.0 ROM作者 雪狼团队-大盛   http://weibo.com/DaShengdd Android版本 ...

  7. unity3d格式的导出与加载

    http://blog.csdn.net/nateyang/article/details/7567831 1.导出.unity3d格式资源: http://game.ceeger.com/Scrip ...

  8. 乐鑫esp8266的串口通讯驱动源文件,nonos和rtos版本

    目录 一.前言: 二.esp8266的串口分布情况: 三.esp8266的串口通讯时候,应该怎么接线: 四.esp8266的NONOS非系统,串口编程: 五.esp8266的RTOS实时系统,串口编程 ...

  9. Android 6.0 超级简单的权限申请2 (Permission)

    代码地址如下:http://www.demodashi.com/demo/13506.html 写在前面 上次写了一个权限申请的例子Android 6.0 超级简单的权限申请 (Permission) ...

  10. 检查linux网络的状况

    http://hi.baidu.com/dr_wang/blog/item/2952f7458659c306cefca3cc.html