题目:
http://acm.hdu.edu.cn/showproblem.php?pid=3613
题意:
有一个长度为
n
的项链,有
思路:
用
用
kmp
的话,把原串翻转得到反串,用原串去匹配反串,可以得到前缀的回文字符串,用反串去匹配原串,得到后缀的回文字符串,然后枚举分割点
用
extkmp
的话,思路跟
kmp
差不多,只是利用了
extkmp
的性质
manacher:
#include <bits/stdc++.h>
using namespace std;
const int N = 500000 + 10, INF = 0x3f3f3f3f;
int L = 26;
char ori[N], pat[N*2];
int p[N*2];
int val[N], sum[N*2];
void manacher(char *ori)
{
int len = strlen(ori + 1);
for(int i = 1; i <= len; i++) pat[i*2] = ori[i], pat[i*2+1] = '#';
pat[0] = '?', pat[1] = '#';
int k = 0, extk = 0;
for(int i = 2; i <= len*2; i++)
{
p[i] = (i < extk) ? min(p[2*k-i], extk-i) : 1;
while(pat[i+p[i]] == pat[i-p[i]]) p[i]++;
if(i + p[i] > extk) k = i, extk = i + p[i];
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
for(int i = 1; i <= L; i++) scanf("%d", &val[i]);
scanf(" %s", ori + 1);
manacher(ori);
int len = strlen(ori + 1);
for(int i = 1; i <= 2*len; i++)
{
if(i & 1) sum[i] = sum[i-1];
else sum[i] = sum[i-1] + val[pat[i]-'a'+1];
}
int ans = -INF;
for(int i = 3; i <= len*2; i += 2)
{
int x = (i + 1) / 2, y = (i + len*2 + 1) / 2;
int t1 = 0, t2 = 0;
if(x + p[x] - 1 >= i) t1 = sum[i];
if(y - p[y] + 1 <= i) t2 = sum[len*2] - sum[i];
ans = max(ans, t1 + t2);
}
printf("%d\n", ans);
}
return 0;
}
kmp:
#include <bits/stdc++.h>
using namespace std;
const int N = 500000 + 10, INF = 0x3f3f3f3f;
char ori[N], pat[N];
int Next[N];
int L = 26, val[30];
int sum[N];
bool vis1[N], vis2[N];
void get_next(char *pat)
{
int i = 0, j = -1;
Next[0] = -1;
while(pat[i])
{
if(j == -1 || pat[i] == pat[j]) Next[++i] = ++j;
else j = Next[j];
}
}
int kmp(char *ori, char *pat)
{
get_next(pat);
int i = 0, j = 0;
while(ori[i])
{
if(j == -1 || ori[i] == pat[j]) ++i, ++j;
else j = Next[j];
}
return j;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
for(int i = 0; i < L; i++) scanf("%d", &val[i]);
scanf(" %s", ori);
int len = strlen(ori);
for(int i = 0; i < len; i++) pat[i] = ori[i], sum[i+1] = sum[i] + val[ori[i]-'a'];
//for(int i = 1; i <= len; i++) vis1[i] = vis2[i] = false;
memset(vis1, 0, sizeof vis1);
memset(vis2, 0, sizeof vis2);
reverse(pat, pat + len);
int k = kmp(pat, ori);
while(k) vis1[k] = true, k = Next[k];
k = kmp(ori, pat);
while(k) vis2[k] = true, k = Next[k];
int ans = -INF;
for(int i = 1; i <= len-1; i++)
{
int num = 0;
if(vis1[i] == true) num += sum[i];
if(vis2[len-i] == true) num += sum[len] - sum[i];
ans = max(ans, num);
}
printf("%d\n", ans);
}
return 0;
}
extkmp:
#include <bits/stdc++.h>
using namespace std;
const int N = 500000 + 10, INF = 0x3f3f3f3f;
char ori[N], pat[N];
int Next[N], extend[N];
int L = 26, val[30];
int sum[N], a[N], b[N];
void get_next(char *pat)
{
int len = strlen(pat);
Next[0] = len;
int k = 0;
while(k + 1 < len && pat[k] == pat[k+1]) ++k;
Next[1] = k;
k = 1;
for(int i = 2; pat[i]; i++)
{
if(i + Next[i-k] < k + Next[k]) Next[i] = Next[i-k];
else
{
int j = max(k + Next[k] - i, 0);
while(i + j < len && pat[j] == pat[i+j]) ++j;
Next[i] = j;
k = i;
}
}
}
void extkmp(char *ori, char *pat)
{
get_next(pat);
int k = 0, leno = strlen(ori), lenp = strlen(pat);
while(k < leno && k < lenp && ori[k] == pat[k]) ++k;
Next[0] = k;
k = 0;
for(int i = 1; ori[i]; i++)
{
if(i + Next[i-k] < k + extend[k]) extend[i] = Next[i-k];
else
{
int j = max(k + extend[k] - i, 0);
while(i + j < leno && j < lenp && ori[i+j] == pat[j]) ++j;
extend[i] = j;
k = i;
}
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
for(int i = 0; i < L; i++) scanf("%d", &val[i]);
scanf(" %s", ori);
int len = strlen(ori);
for(int i = 0; i < len; i++) pat[i] = ori[i], sum[i+1] = sum[i] + val[ori[i]-'a'];
reverse(pat, pat + len);
extkmp(ori, pat);
memcpy(a, extend, sizeof extend);
extkmp(pat, ori);
memcpy(b, extend, sizeof extend);
int ans = -INF;
for(int i = 1; i <= len-1; i++)
{
int num = 0;
if(i + a[i] == len) num += sum[len] - sum[i];
if(len-i + b[len-i] == len) num += sum[i];
ans = max(ans, num);
}
printf("%d\n", ans);
}
return 0;
}