【字符串入门专题1】hdu3613 【一个悲伤的exkmp】


Best Reward




Problem Description
After an uphill battle, General Li won a great victory. Now the head of state decide to reward him with honor and treasures for his great exploit. 

One of these treasures is a necklace made up of 26 different kinds of gemstones, and the length of the necklace is n. (That is to say: n gemstones are stringed together to constitute this necklace, and each of these gemstones belongs to only one of the 26 kinds.) 

In accordance with the classical view, a necklace is valuable if and only if it is a palindrome - the necklace looks the same in either direction. However, the necklace we mentioned above may not a palindrome at the beginning. So the head of state decide to cut the necklace into two part, and then give both of them to General Li. 

All gemstones of the same kind has the same value (may be positive or negative because of their quality - some kinds are beautiful while some others may looks just like normal stones). A necklace that is palindrom has value equal to the sum of its gemstones' value. while a necklace that is not palindrom has value zero. 

Now the problem is: how to cut the given necklace so that the sum of the two necklaces's value is greatest. Output this value. 

 

Input
The first line of input is a single integer T (1 ≤ T ≤ 10) - the number of test cases. The description of these test cases follows. 

For each test case, the first line is 26 integers: v1, v2, ..., v26 (-100 ≤ vi ≤ 100, 1 ≤ i ≤ 26), represent the value of gemstones of each kind. 

The second line of each test case is a string made up of charactor 'a' to 'z'. representing the necklace. Different charactor representing different kinds of gemstones, and the value of 'a' is v1, the value of 'b' is v2, ..., and so on. The length of the string is no more than 500000. 

 

Output
Output a single Integer: the maximum value General Li can get from the necklace.
 

Sample Input
2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 aba 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 acacac
 

Sample Output
1 6



题意:这道题的题意真难get到,先输入n,再输入n组样例,每组样例先输入a~z对应的价值,再输入由a~z组成的字符串,要求把字符串二分后,串1是回文串,串2也是回文串,这样最大价值就是串1和串2的价值相加,否则为0
思路:把s1倒置后为s2,用exkmp函数进行扩展,如果s1的前i个字符等于s2的后i个字符,即ex2[l-i] == i 时,说明s1的前i个字符是回文串,判断后l-i个字符串是否为回文串,再用一次exkmp函数就行啦
~~这这这这绝对是一个悲伤的exkmp,由于这道题方法有很多,我在网上找到的exkmp代码就只有一家能看,(为啥我对exkmp这么执着啊。。)略带强迫的我还特地改了代码格式来看,以为get到了方法,自己还让学姐把练习时间加到中午,然后,队友他们饿着肚子等我得到一个wrong answer,之后就是漫长的debug....,结果发现是自己把ex1和ex2的作用搞混了,ex2存的是s2的任意后缀和s1的前缀最大公共长度,我们通过判断ex2[l-i]==i   来说明s1的前i个字符等于s2的后i个字符,进而说明串的前i个字符为回文串。ex1存的是s1的任意后缀和s2的前缀最长公共长度,我们通过判断ex1[i] == l-i 来说明s1的后l-i个字符等于s2的前l-i个字符,进而说明串的后l-i个字符是回文串。

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
#define N 550000

char s1[N],s2[N];
int ex1[N],ex2[N],v[N];
int b1[N],b2[N];
int s[27];
int t;

void exkmp(char s1[],char s2[],int next[],int ex[])
{
    int i,j,p;
    i = j = 0;
    p = -1;
    while(s1[i]!='')
    {
        if(p == -1)
        {
            j = 0;
            do
                p++;
            while(s1[i+p]!=''&&s1[i+p]==s2[j+p]);
            ex[i] = p;
        }
        else if(next[j]>p)
            ex[i] = p;
        else if(next[j]<p)
            ex[i] = next[j];
        else
        {
            j = 0;
            while(s1[i+p]!=''&&s2[j+p] == s1[i+p])
            	p++;
            ex[i] = p;
        }
        i++;
        j++;
        p--;
    }
    ex[i] = 0;
    return;
}
int main()
{
    int i,j,sum,ans,l;
    scanf("%d",&t);
    while(t --)
    {
        getchar();
        memset(v,0,sizeof(v));
        memset(b1,0,sizeof(b1));
        memset(b2,0,sizeof(b2));
        for(i = 0; i < 26; i ++)
            cin>>s[i];

        scanf("%s",s1);
        l = strlen(s1);
        for(i = 1; i <= l; i ++)
        {
            v[i] = v[i-1]+ s[s1[i-1]-'a'];
            s2[i-1] = s1[l-i];
        }
        exkmp(s2+1,s2,b1,b1+1);//调用一次exkmp函数计算s2的next数组 
        exkmp(s1,s2,b1,ex1);//再次调用exkmp函数计算s1的任意后缀和s2前缀最长公共长度的ex1数组 
         
        exkmp(s1+1,s1,b2,b2+1);//调用函数计算s1的next数组 
        exkmp(s2,s1,b2,ex2);//计算s2的任意后缀和s1的前缀最长公共长度的ex2数组 
    
        ans = sum = 0;
        for(i = 1; i < l; i ++)
        {
            if(ex2[l-i] == i)//串的前i个字符是回文串 
                sum += v[i]; 
            if(ex1[i] == l-i)//串的后l-i个字符是回文串 
                sum += v[l] - v[i];
            if(sum > ans )
                ans = sum;
            sum = 0;
        }
        printf("%d
",ans);
    }
    return 0;
}


























原文地址:https://www.cnblogs.com/hellocheng/p/7350055.html