题目
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; }