标签:some imu std target turn 说明 use container normal
题目链接:
https://cn.vjudge.net/problem/HDU-3613
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 acacacSample Output
1 6
解题思路:
问题的关键还是如何判断从某个位置分割开后,前缀和后缀是否是回文串
这次采用拓展kmp算法求解,关于拓展kmp的介绍请参考另一篇博客:https://www.cnblogs.com/wenzhixin/p/9355480.html
先将s1反转赋值给s2,用s1去匹配s2,得到s2中每个后缀与s1的最长公共前缀数组extpre
用s2去匹配s1,得到s1中每个后缀与s2的最长公共前缀数组extpos
再枚举每一个分割点,判断,求值,更新答案取最优。
关键是如何使用extend数组,举个例子来说
abcde
当分割长度为2的时候,需要分别判断ab和bcde是否是回文串
先看ab,要看ab是否是回文串需要用到extpre数组,为什么用到它而不是另一个分析如下:
用s2去匹配s1制作的到extpre数组
s2 edcba
s1 abcde
要判断ab是否是回文串,就是看ba与s1的最长公共前缀是多少,如果恰好是ba的长度,就说明ba在原串中存在。也即extpre[ls - i] == i(其中ls是串的总长度)。同时又有两者逆序,必然是回文串。
再看bcde是否是回文串
用s1去匹配s2制作的到extpos数组
s1 abcde
s2 edcba
要判断bcde是否是回文串,就要看bcde与s2的最长公共前缀是多少,如果恰好是dcde的长度,就说明bcde在反串中存在。也即extpre[i] == ls - i(其中ls是串的总长度)。同时又有两者逆序,必然是回文串。
这样就完成了,是否是回文串的判断。
代码实现:
1 #include<cstdio> 2 #include<cstring> 3 4 const int maxn = 500010; 5 int val[26], presum[maxn], next[maxn], extpre[maxn], extpos[maxn]; 6 char s1[maxn], s2[maxn]; 7 8 void exkmp(char s[], char t[], int len, int ex[]); 9 void get_next(char t[], int len); 10 11 int main() 12 { 13 int T; 14 scanf("%d", &T); 15 16 while(T--){ 17 for(int i = 0; i < 26; i++){ 18 scanf("%d", &val[i]); 19 } 20 scanf("%s", s1); 21 int ls = strlen(s1); 22 presum[0] = 0; 23 for(int i = 0;i < ls; i++){ 24 s2[ls - 1 - i] = s1[i]; 25 presum[i + 1] = presum[i] + val[s1[i] - ‘a‘]; 26 } 27 s2[ls] = ‘\0‘; 28 29 exkmp(s2, s1, ls, extpre);//拿s1去匹配s2,得到s2中每个后缀与s1的最长公共前缀数组extpre 30 exkmp(s1, s2, ls, extpos);//拿s2去匹配s1,得到s1中每个后缀与s2的最长公共前缀数组extpos 31 32 int ans = -99999999; 33 for(int i = 1; i <= ls - 1; i++){//在长度为 i 处分割 34 int sum = 0; 35 if(extpre[ls - i] == i) 36 sum += presum[i]; 37 if(extpos[i] == ls - i) 38 sum += presum[ls] - presum[i]; 39 if(sum > ans) 40 ans = sum; 41 } 42 printf("%d\n", ans); 43 } 44 return 0; 45 } 46 47 void get_next(char t[], int len){ 48 next[0] = len; 49 int k = 1; 50 while(k < len && t[k] == t[k - 1]) 51 k++; 52 next[1] = k; 53 54 int po = 1; 55 for(k = 2; k< len; k++){ 56 if(next[k - po] + k < next[po] + po) 57 next[k] = next[k - po]; 58 else{ 59 int j = next[po] + po - k; 60 if(j < 0) 61 j = 0; 62 while(k + j < len && t[k] == t[k + j]) 63 j++; 64 65 next[k] = j; 66 po = k; 67 } 68 } 69 70 } 71 72 void exkmp(char s[], char t[], int len, int ex[]) 73 { 74 memset(next, 0, sizeof(next)); 75 get_next(t, len); 76 77 int k=0; 78 while(k < len && s[k] == t[k]) 79 k++; 80 ex[0] = k; 81 82 int po = 0; 83 for(k = 1; k< len; k++){ 84 if(next[k - po] + k < ex[po] + po) 85 ex[k] = next[k - po]; 86 else{ 87 int j = ex[po] + po - k; 88 if(j < 0) 89 j = 0; 90 91 while(k + j < len && j < len && s[k + j] == t[j]) 92 j++; 93 ex[k] = j; 94 po = k; 95 } 96 } 97 }
HDU 3613 Best Reward(拓展KMP算法求解)
标签:some imu std target turn 说明 use container normal
原文地址:https://www.cnblogs.com/wenzhixin/p/9355880.html