[ZOJ 3807 Just a Palindrome] 字符串hash+二分

题目

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3807

分析

字符串hash

首先像manacher一样把字符串倍长用‘#’隔开,然后枚举中心点

找出两侧第一个不一样的位置x1和y1

找出两侧第二个不一样的位置x2和y2

找出两侧第三个不一样的位置x3和y3

可以用hash+二分解决

那么共有三种情况:

一是x1或y1跟中心交换

二是x1或y1跟最左或最右的与y1或x1相同的交换

三是x1和y2、y1和x2互相交换,分别讨论即可

状态不太好,打错了好多细节

代码

/**************************************************
 *        Problem:  ZOJ 3807
 *         Author:  clavichord93
 *          State:  Accepted
 **************************************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

template <class T>
inline void gmax(T &a, T b) {
    if (a < b) {
        a = b;
    }
}

const int MAX_N = 200005;

int n;
char str[MAX_N];
char s[MAX_N];

int idx[256];
int leftMost[256];
int rightMost[256];

long long hashLeft[MAX_N];
long long hashRight[MAX_N];
long long pow131[MAX_N];

int getLength(int x, int y, int limit) {
    int l = 1, r = limit;
    int ans = 0;
    while (l <= r) {
        int mid = (l + r) >> 1;
        long long hash1 = (hashRight[x - mid + 1] - hashRight[x + 1]) * pow131[y - 1];
        long long hash2 = (hashLeft[y + mid - 1] - hashLeft[y - 1]) * pow131[n - x];
        if (hash1 == hash2) {
            ans = mid;
            l = mid + 1;
        }
        else {
            r = mid - 1;
        }
    }
    return ans;
}

int main() {
    #ifdef LOCAL_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    #endif

    for (int i = 'a'; i <= 'z'; i++) {
        idx[i] = i - 'a' + 1;
    }
    for (int i = 'A'; i <= 'Z'; i++) {
        idx[i] = i - 'A' + 27;
    }

    pow131[0] = 1;
    for (int i = 1; i <= 200001; i++) {
        pow131[i] = pow131[i - 1] * 131ll;
    }

    int cas = 0;
    while (scanf("%s", str + 1) != EOF) {
        memset(hashLeft, 0, sizeof(hashLeft));
        memset(hashRight, 0, sizeof(hashRight));
        memset(leftMost, 0, sizeof(leftMost));
        memset(rightMost, 0, sizeof(rightMost));

        n = strlen(str + 1);
        s[1] = idx[(int)str[1]];
        for (int i = 2; i <= n; i++) {
            s[2 * i - 2] = 0;
            s[2 * i - 1] = idx[(int)str[i]];
        }
        n = n + n - 1;

        for (int i = 1; i <= n; i++) {
            hashLeft[i] = hashLeft[i - 1] + s[i] * pow131[i - 1];
        }
        for (int i = n; i >= 1; i--) {
            hashRight[i] = hashRight[i + 1] + s[i] * pow131[n - i];
        }

        for (int i = 1; i <= n; i++) {
            rightMost[(int)s[i]] = i;
        }
        for (int i = n; i >= 1; i--) {
            leftMost[(int)s[i]] = i;
        }

        int ans = 0;
        for (int i = 1; i <= n; i++) {
            int length = min(i - 1, n - i);
            int length1 = getLength(i - 1, i + 1, length);
            int x1 = i - length1 - 1;
            int y1 = i + length1 + 1;
            int a = s[x1];
            int b = s[y1];
            int totLength = 0;
            // No Swap
            totLength = length1;
            if (length1 < length) {
                length = min(x1 - 1, n - y1);
                int length2 = getLength(x1 - 1, y1 + 1, length);
                int x2 = x1 - length2 - 1;
                int y2 = y1 + length2 + 1;
                // Replace A with s[i] or Replace B with s[i]
                if (s[i] == b || s[i] == a) {
                    gmax(totLength, length1 + 1 + length2);
                }
                // Replace A with rightMost B
                if (rightMost[b] > y1) {
                    gmax(totLength, min(y2 - 1, rightMost[b] - 1) - i);
                }
                // Replace A with leftMost B
                if (leftMost[b] < x1) {
                    gmax(totLength, i - max(x2 + 1, leftMost[b] + 1));
                }
                // Replace B with rightMost A
                if (rightMost[a] > y1) {
                    gmax(totLength, min(y2 - 1, rightMost[a] - 1) - i);
                }
                // Replace B with leftMost A
                if (leftMost[a] < x1) {
                    gmax(totLength, i - max(x2 + 1, leftMost[a] + 1));
                }
                // Cross Swap
                if (length2 < length) {
                    int _a = s[x2];
                    int _b = s[y2];
                    if ((_a == a && b == _b) || (_a == b && _b == a)) {
                        length = min(x2 - 1, n - y2);
                        int length3 = getLength(x2 - 1, y2 + 1, length);
                        gmax(totLength, length1 + 1 + length2 + 1 + length3);
                    }
                }
            }
            if (s[i]) {
                gmax(ans, totLength / 2 * 2 + 1);
            }
            else {
                gmax(ans, (totLength + 1) / 2 * 2);
            }
        }

        printf("Case %d: %d\n", ++cas, ans);
    }

    return 0;
}


你可能感兴趣的:([ZOJ 3807 Just a Palindrome] 字符串hash+二分)