Best Reward HDU 3613(回文子串Manacher)

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

 

分析:首先的明白这个最大价值有可能是负数,比如下面:

-1 -1 -1.....

aaa

这样的情况不管怎么分,分出来的串都是回文串,所以得到的最大价值是 -3。

求回文串的算法使用的是Manacher算法,线性的复杂度。

 

代码如下:

================================================================================================================

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int MAXN = 1e6+7;
const int MAXM = 1007;
const int oo = 1e9+7;
char str[MAXN];
int p[MAXN], val[27], sum[MAXN];
bool Left[MAXN], Right[MAXN];

/**
str[]   先存原字符串,后存扩展后的字符串
p[]     p[i] 表示以i为中心的回文串有多长(只记录一边的长度)、
sum[]   sum[i]表示前i个字符的总价值和
Left[]  Left[i] 表示前缀长度为 i 的串是否是回文串
Right[] Right[i]  表示后缀长度为 i 的串是否是回文串
**/

void Manacher(char str[], int N)
{
    int i, id=0;

    for(i=2; i<N; i++)
    {
        if(p[id]+id > i)
            p[i] = min( p[id*2-i], p[id]+id-i);
        else p[i] = 1;

        while(str[ i+p[i] ] == str[ i-p[i] ])
            p[i]++;

        if(p[id]+id < p[i]+i)
            id = i;

        if(p[i] == i)
            Left[p[i]-1] = true;
        if(p[i]+i-1 == N)
            Right[p[i]-1] = true;
    }
}

int main()
{
    int T;

    scanf("%d", &T);

    while(T--)
    {
        int i;

        memset(Left, false, sizeof(Left));
        memset(Right, false, sizeof(Right));
        memset(p, false, sizeof(p));

        for(i=0; i<26; i++)
            scanf("%d", &val[i]);

        scanf("%s", str);

        int len = strlen(str);

        for(i=1; i<=len; i++)
            sum[i] = sum[i-1]+val[str[i-1]-‘a‘];

        for(i=len; i>=0; i--)
        {
            str[i+i+2] = str[i];
            str[i+i+1] = ‘#‘;
        }
        str[0] = ‘$‘;

        Manacher(str, len+len+1);

        int ans = -oo;

        for(i=1; i<len; i++)
        {
            int temp = 0;

            if(Left[i] == true)
                temp += sum[i];
            if(Right[len-i] == true)
                temp += sum[len]-sum[i];

            ans = max(ans, temp);
        }

        printf("%d\n", ans);
    }

    return 0;
}
时间: 2024-10-10 06:36:53

Best Reward HDU 3613(回文子串Manacher)的相关文章

Girls&#39; research---hdu3294(回文子串manacher)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3294 给出一个字符串和加密的字符规律 例如 c abcba c代表把串中的c改成a,d改成b... b改成z,a改成y... 即上串是yzazy,然后求出它的最长回文子串, 并记录子串的开始下标和结束下标就行了: #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; con

HiHo 1032 最长回文子串 (Manacher算法求解)

Manacher算法o(n)求解最长回文子串问题 非常巧妙 #include<bits/stdc++.h> using namespace std; char str[2000020],s[2000020]; int p[2000020]; int len,id,mx; void pre() //对字符串进行预处理 { len=strlen(s); str[0]='$'; str[1]='#'; for(int i=0;i<len;i++) { str[i*2+2]=s[i]; str[

最长回文子串Manacher算法模板

Manacher算法能够在O(N)的时间复杂度内得到一个字符串以任意位置为中心的回文子串.其算法的基本原理就是利用已知回文串的左半部分来推导右半部分. 例题:HDU 3068 1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 using namespace std; 5 const int N=110005; 6 char s[N],cpy[N<<1]; 7 int rad[N&l

hiho#1032 : 最长回文子串 (manacher算法O(n)时间求字符串的最长回文子串 )

#1032 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:"小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?" 小Ho奇怪的问道:"什么叫做最长回文子串呢?" 小Hi回答道:"一个字符串中连续的一

hihocoder 1032 : 最长回文子串(Manacher)

之前做过类似的题,只是理解了,还没达到驾轻就熟,想到即敲出的地步,所以再练一次. 顺带将Manacher算法思想解释一遍,加强印象,也算作分享吧. Manacher 我们用f(x)表示以x位置为中心的回文串的长度 j相对i的对应位置是j' 那么f(j)与f(j')和f(i)有什么关系呢. 先看第一张图,下面那条横杠表示f(i),那么,既然j'与j相对应,j'的回文串长度已经求出,那么j位置的回文串长度一定是大于等于j'长度的. 即f(i) >= f(j')=f(i*2-j) 但是还存在上图这样的

hihoCoder #1032 : 最长回文子串 [ Manacher算法--O(n)回文子串算法 ]

传送门 #1032 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:“小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?” 小Ho奇怪的问道:“什么叫做最长回文子串呢?” 小Hi回答道:“一个字符串中连续的一段就是这个字符串的子串,而回文串

最长回文子串 - Manacher算法

算法思想: 设有字符串s[] = "121" 第一步:通过在每个字符左右都添加一个特殊字符,把奇数长度和偶数长度的字符串都转化成奇数(例如. "121" 加上特殊字符后变成"#1#2#1" ),同时也可在开头再加一个特殊字符,以便于忽略越界问题(如上例"121"变成"$#1#2#1#"  此时开头的特殊字符$和字符串末尾的\0与此串中其他字符都不同,即可忽略越界问题),此时字符串变成 s[] = "

吉哥系列故事——完美队形II---hdu4513(最长回文子串manacher)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4513 题意比最长回文串就多了一个前面的人要比后面的人低这个条件,所以在p[i]++的时候判断一下s[i-p[i]]<=s[i-p[i]+2]就可以了; 用最长回文串算法manacher:套一下模板就可以了: #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; con

求最长回文子串——Manacher算法

回文串包括奇数长的和偶数长的,一般求的时候都要分情况讨论,这个算法做了个简单的处理把奇偶情况统一了.算法的基本思路是这样的,把原串每个字符中间用一个串中没出现过的字符分隔开来(统一奇偶),用一个数组p[ i ]记录以 str[ i ] 为中间字符的回文串向右能匹配的长度.先看个例子 原串:       w  a   a   b   w   s   w   f   d 新串(str):  #   w  #   a   #   a   #   b  #   w   #   s    #   w