题目大意:给你26个字符对应的价值和一个字符串,要求你将字符串分成两个部分。分开后,如果那部分是回文的话,那么价值就是该部分字符的价值和,如果不是回文,价值为0,问分开后的最大价值和
解题思路:可以用KMP做也可以用拓展KMP做
KMP做的话,假设原字符串是s1,然后将字符串倒转变成s2,先求s1的后缀和s2的前缀匹配的部分,这部分是s1的后缀的回文部分,然后再通过next数组,找出所有的回文,并标记
接下来求出s2的后缀和s1的前缀的匹配部分,这部分就是s1前缀的回文部分了,同理,通过next数组求出所有的回文部分,并标记
接下来就是枚举每个位置了
#include <cstdio>
#include <cstring>
const int INF = 0x3f3f3f3f;
const int N = 500010;
int val[30], sum[N];
int next[N];
int len, test;
char s1[N], s2[N];
int pre[N], suf[N];
void init() {
for (int i = 0; i < 26; i++)
scanf("%d", &val[i]);
scanf("%s", s1);
len = strlen(s1);
for (int i = 0; i < len; i++) {
s2[i] = s1[len - i - 1];
sum[i + 1] = sum[i] + val[s1[i] - 'a'];
}
}
void getNext(char *s1, int *next) {
int i = 0, j = -1;
next[0] = -1;
while (i < len) {
if (j == -1 || s1[i] == s1[j]) next[++i] = ++j;
else j = next[j];
}
}
int KMP(char *s1, char *s2) {
int i = 0, j = 0;
while (i < len) {
if (j == -1 || s1[j] == s2[i]) {
j++; i++;
}
else j = next[j];
}
return j;
}
void solve() {
getNext(s1, next);
int t = KMP(s1, s2);
while (t) {
pre[t] = test + 1;
t = next[t];
}
getNext(s2, next);
t = KMP(s2, s1);
while (t) {
suf[t] = test + 1;
t = next[t];
}
int ans = -INF, tmp = 0;
for (int i = 1; i < len; i++) {
if (pre[i] == test + 1) tmp += sum[i];
if (suf[len - i] == test + 1) tmp += sum[len] - sum[i];
if (tmp > ans) ans = tmp;
tmp = 0;
}
printf("%d\n", ans);
}
int main() {
scanf("%d", &test);
while (test--) {
init();
solve();
}
return 0;
}
拓展KMP的话,和上面的差不多,也是翻转后求公共前缀的
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 500010;
char s1[N], s2[N];
int len;
int val[30], sum[N], Next[N], ex1[N], ex2[N];
void init() {
for (int i = 0; i < 26; i++)
scanf("%d", &val[i]);
scanf("%s", s1);
len = strlen(s1);
for (int i = 0; i < len; i++) {
sum[i + 1] = sum[i] + val[s1[i] - 'a'];
s2[len - i - 1] = s1[i];
}
}
void getNext(char *s1) {
Next[0] = len;
int i;
for (i = 0; s1[i] == s1[i + 1]; i++);
Next[1] = i;
int a = 1;
for (int k = 2; k < len; k++) {
int p = a + Next[a] - 1, L = Next[k - a];
if (k + L - 1 >= p) {
int j = max(p - k + 1, 0);
while (k + j < len && s1[j] == s1[k + j]) j++;
Next[k] = j;
a = k;
}
else Next[k] = L;
}
}
void EDKMP(char *s1, char *s2, int *ex) {
getNext(s1);
int i = 0;
for (; s1[i] == s2[i] && i < len; i++);
ex[0] = i;
int a = 0;
for (int k = 1; k < len; k++) {
int p = ex[a] + a - 1, L = Next[k - a];
if (k + L - 1 >= p) {
int j = max(p - k + 1, 0);
while (k + j < len && s1[j] == s2[j + k]) j++;
ex[k] = j;
a = k;
}
else ex[k] = L;
}
}
void solve() {
EDKMP(s1, s2, ex1);
EDKMP(s2, s1, ex2);
int ans = 0, tmp = 0;
for (int i = 1; i < len; i++) {
if (ex1[len - i] == i) tmp += sum[i];
if (ex2[i] == len - i) tmp += sum[len] - sum[i];
if (tmp > ans) ans = tmp;
tmp = 0;
}
printf("%d\n", ans);
}
int main() {
int test;
scanf("%d", &test);
while (test--) {
init();
solve();
}
return 0;
}