HDU 3613 Best Reward ( 拓展KMP求回文串 || Manacher )

题意 : 给个字符串S,要把S分成两段T1,T2,每个字母都有一个对应的价值,如果T1,T2是回文串,那么他们就会有一个价值,这个价值是这个串的所有字母价值之和,如果不是回文串,那么这串价值就为0。问最多能获得多少价值?

 

分析 : 有两种做法,第一种是拓展KMP正反跑两次或者Manacher

①如果我们用原串去和反转串( 即将原串反转 )跑一次拓展KMP得到的 extend 能够帮助我们得到原串前缀的某一段是否是回文串,仅当 extend[i] = 整个后缀长度,而用反转串去和原串跑一次拓展KMP得到的另一个 extend 能够帮助我们得到原串的某个后缀是否是回文串,借助这两个 extend 我们就能得到每一个字符作为分割点时候的价值了,当然提前处理原串的前缀价值和会快速更多

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
const int maxn = 5e5 + 10;
int Next[maxn], moL;
void GetNext(char * mo)
{
    Next[0] = moL;
    int a, p;
    for (int i = 1, j = -1; i < moL; i++, j--){
        if (j < 0 || i + Next[i - a] >= p){
            if (j < 0) p = i, j = 0;

            while (p < moL && mo[p] == mo[j]) p++, j++;

            Next[i] = j;
            a = i;
        } else Next[i] = Next[i - a];
    }
}

void GetExtend(char * S, char *mo, int * ext)
{
    GetNext(mo);
    int a, p;
    int strL = moL;
    for (int i = 0, j = -1; i < strL; i++, j--){
        if (j < 0 || i + Next[i - a] >= p){
            if (j < 0) p = i, j = 0;

            while (p < strL && j < moL && S[p] ==  mo[j])
                p++, j++;

            ext[i] = j;
            a = i;
        } else ext[i] = Next[i - a];
    }
}

int sum[maxn], val[27];

inline void GetSum(char * mo)
{
    memset(sum, 0, sizeof(sum));
    sum[0] = val[mo[0]-'a'];
    for(int i=1; i<moL; i++){
        sum[i] += sum[i-1] + val[mo[i]-'a'];
    }
}

char mo[maxn], Rmo[maxn];
int extend[maxn], Rextend[maxn];

int main(void)
{
    int nCase;
    scanf("%d", &nCase);
    while(nCase--){
        for(int i=0; i<26; i++)
            scanf("%d", &val[i]);
        scanf("%s", mo);
        memcpy(Rmo, mo, sizeof(mo));
        moL = strlen(mo);
        std::reverse(Rmo, Rmo+moL);
        
        GetSum(mo);
        GetExtend(Rmo, mo, extend);///用原串跑反转串
        GetExtend(mo, Rmo, Rextend);///用反转串跑原串

        int ans = 0;
        for(int i=1; i<moL; i++){
            int tmp = 0;
            if(extend[i] == moL-i) tmp += sum[moL-i-1];///这里的关系可能有点烦,拿个例子推一推就行了
            if(Rextend[moL-i] == i) tmp += sum[moL-1]-sum[moL-i-1];
            ans = max(tmp, ans);
        }

        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

②如果用Manacher的话就每一个字符串去跑一下最长回文算法,然后和①一样的处理即可,当然代码会更简单,而且时间复杂度上也比①优

posted @ 2017-09-26 19:45  qwerity  阅读(149)  评论(0编辑  收藏  举报