标签:
Mean:
给你一个字符串,每个字符都有一个权值(可能为负),让你将这个字符串分成两个字串,使得这两个子串的价值之和最大。一个子串价值的计算方法:如果这个子串是回文串,那么价值就是这个子串所有字符权值之和;否则价值为0。
analyse:
经典的扩展KMP算法运用。
假设输入串为s,那么我们首先:strcpy(s1,s) ; s_tmp=s.reverse() ; s1[s1.length()]=‘#‘ strcat(s1,s_tmp);
根据s1求一遍next,我们就可以得到所有以s[0]开头的子串的回文串长度;
然后:
strcpy(s2,s_tmp) ; s2[s2.length()]=‘#‘; strcat(s2,s);
根据s2求一遍next,我们就可以得到所有以s[len-1]结尾的子串的回文串长度。
最后只需从头到位扫一遍,每次判断前半部分是不是回文和后半部分是不是回文,然后求出最大值即可。
Time complexity: O(nlogn)
Source code:
/* * this code is made by crazyacking * Verdict: Accepted * Submission Date: 2015-05-06-22.02 * Time: 0MS * Memory: 137KB */ #include <cstdio> #include <string> #include <stack> #include <cmath> #include <set> #include <map> #include <cstdlib> #include <climits> #include <vector> #include <iostream> #include <algorithm> #include <cstring> #define MAXN 500005 #define LL long long using namespace std; char s[MAXN<<1]; int Next[MAXN<<1],value[30]; int sum[MAXN],v[2][MAXN]; int n,m; void get_Next() { int i=0,j=-1; Next[0]=-1; for(;i<m;) if(j==-1||s[i]==s[j]) { ++i;++j; Next[i]=j; } else j=Next[j]; } void check(int x) { sum[0]=0; for(int i=0;i<n;++i) sum[i+1]=sum[i]+value[s[i]-‘a‘]; reverse_copy(s,s+n,s+n+1); s[n]=‘#‘; get_Next(); memset(v[x],0,sizeof(v[x])); int p=m; for(;;) { p=Next[p]; if(!p) break; v[x][p]=sum[p]; } } int main() { int cas; scanf("%d",&cas); for(;cas--;) { int ans=INT_MIN; for(int i=0;i<26;++i) scanf("%d",&value[i]); scanf("%s",s); n=strlen(s); m=2*n+1; check(0); reverse(s,s+n); check(1); reverse(v[1],v[1]+n+1); for(int i=1;i<n;++i) ans=max(ans,v[0][i]+v[1][i]); printf("%d\n",ans); } return 0; }
扩展KMP --- HDU 3613 Best Reward
标签:
原文地址:http://www.cnblogs.com/crazyacking/p/4483476.html