zoukankan      html  css  js  c++  java
  • 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
    ", ans);
        }
        return 0;
    }
    View Code

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

  • 相关阅读:
    消息队列系列——启蒙(一)
    重新整理数据结构与算法(c#)—— 图的深度遍历和广度遍历[十一]
    重新整理数据结构与算法——八皇后问题解决[十]
    重新整理数据结构与算法——迷宫算法[九]
    重新整理数据结构与算法——逆波兰表达计算器[八]
    lowdb 在electron 使用中注意的问题
    apollo客户端springboot实战(四)
    apollo在liunx环境实战(三)
    apollo入门demo实战(二)
    设计模式总结
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/7598534.html
Copyright © 2011-2022 走看看