HDU 3613 Manacher应用

来源:互联网 发布:yum mirrorlist 编辑:程序博客网 时间:2024/05/21 07:39

题意:上面的数字是26个字母的价值,接下来26个英文字母组成的字符串,将它分成两份,如果分后的串是回文串,则这个串的价值是这个串的所有字母的和,如果不是回文串则这个串价值为0。求最大价值和。

看到回文串,第一时间可以想到manacher算法。只要得到了以第i位为中心的最长回文串长度的一半ansi,便不难解决此题。

我们可以枚举切割点i,容易求出左子串的中心lmid和右子串的中心rmid,若要判断左子串是否回文,只需判断lmid+anslmid是否等于i即可,右子串同理,不过加变成减。

如果某一子串回文,我们就要计算它的价值和。这时候每一次都计算显然会很慢,我们可以用部分和Θ(n)预处理,要用的时候直接Θ(1)计算。

到这里问题就基本解决了,时间复杂度也只是线性的。

#include <algorithm>#include <climits>#include <cstdio>#include <cstring>using namespace std;const int charset = 26;const int maxlen = 5e5 + 9;int value[charset + 5];int presum[maxlen << 1];char st[maxlen << 1], tmp[maxlen << 1];int len;int f[maxlen << 1];void init() {    for(int i = 0; i < charset; i++) scanf("%d", &value[i]);    scanf("%s", tmp);    st[0] = '!';    len = 1;    int tlen = strlen(tmp);    for(int i = 0; i < tlen; i++) {        st[len++] = '#';        st[len++] = tmp[i];    }    st[len++] = '#';    st[len++] = '?';}void get_sum() {    presum[0] = presum[1] = 0;    presum[2] = value[st[2] - 'a'];    for(int i = 3; i < len; i++) {        presum[i] = presum[i - 1];        if(st[i] != '#') presum[i] += value[st[i] - 'a'];    }}void manacher() {    f[0] = f[1] = 0;    int p = 1;    for(int i = 2; i < len; i++) {        f[i] = max(0, min(f[(p << 1) - i], p + f[p] - i));        while(st[i - f[i] - 1] == st[i + f[i] + 1]) ++f[i];        if(i + f[i] > p + f[p]) p = i;    }}void solve() {    init();    get_sum();    manacher();    int ans = INT_MIN;    int left_mid = 2;    int right_mid = ((len - 4) >> 1) + 3;    for(int i = 3; i + 2 < len; i += 2) {        int s = 0;        if(left_mid + f[left_mid] == i) s += presum[i];        if(right_mid - f[right_mid] == i) s += presum[len - 3] - presum[i];        ++left_mid;        ++right_mid;        ans = max(ans, s);    }    printf("%d\n", ans);}int main() {    freopen("hdu3613.in", "r", stdin);    freopen("hdu3613.out", "w", stdout);    int caset;    scanf("%d", &caset);    for (int casei = 0; casei < caset; casei++) solve();    return 0;}
0 0
原创粉丝点击