zoukankan      html  css  js  c++  java
  • 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
    ", ans);
        }
    
        return 0;
    }
  • 相关阅读:
    实体类、边界类和控制类
    面向对象分析和面向对象设计的区别
    面向对象分析与设计的步骤
    用例图:从用户角度描述系统功能,并指各功能的操作者
    面向对象分析和设计(OOA/D)
    在UML系统开发中有三个主要的模型
    UML建模之活动图介绍(Activity Diagram)
    活动图本质上就是流程图
    流程图
    流程、业务与事务
  • 原文地址:https://www.cnblogs.com/liuxin13/p/4747537.html
Copyright © 2011-2022 走看看