题目链接:https://vjudge.net/problem/HDU-6230
题目大意
给定一个字符串,求这个字符串中有多少个一个半字符串。
一个半字符串:类似于1234543212345。
花絮
模拟赛时一直只思考了 123454321 怎么通过 (O(1)) 的时间复杂度搞出后面的串,导致直接卡死。
思路
1234543212345 是按照5和1对称的,那么在保证5和1是回文串的状态下,要能够之间相互覆盖。
设5的位置为 (i),1的位置为 (j), 要求 (i leq j),则可得公式
( left{egin{matrix} j-i leq len[i] \ j-i leq len[j] \ end{matrix} ight. )
移动式子,可得
( left{egin{matrix} j leq i+len[i] \ j-len[j] leq i \ end{matrix} ight. )
将其转化为区间 ([i+1, i+len[i]]) 内求有多少个数,使得 (j-len[j] leq i)。
AC代码
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN = 5e5 + 5;
class HJT {
public:
int ch[MAXN * 70][2], sum[MAXN * 70];
int tot;
void init() { tot = 0; }
inline void push_up(int rt) {
sum[rt] = sum[ch[rt][0]] + sum[ch[rt][1]];
}
int update(int rt, int pos, int val, int be, int en) {
int nrt = ++tot;
ch[nrt][0] = ch[nrt][1] = sum[nrt] = 0;
if (be == en) {
sum[nrt] = sum[rt] + val;
return nrt;
}
int mid = (be + en) >> 1;
if (pos <= mid) {
ch[nrt][0] = update(ch[rt][0], pos, val, be, mid);
ch[nrt][1] = ch[rt][1];
} else {
ch[nrt][0] = ch[rt][0];
ch[nrt][1] = update(ch[rt][1], pos, val, mid + 1, en);
}
push_up(nrt);
return nrt;
}
int query(int lrt, int rrt, int R, int be, int en) {
if (R == en) return sum[rrt] - sum[lrt];
int mid = (be + en) >> 1;
if (R <= mid) {
return query(ch[lrt][0], ch[rrt][0], R, be, mid);
} else {
return sum[ch[rrt][0]] - sum[ch[lrt][0]] + query(ch[lrt][1], ch[rrt][1], R, mid + 1, en);
}
}
} tree;
void Manacher(char s[], int len, char A[], int B[]) {
int l = 0;
A[l++] = '$';
A[l++] = '#';
for (int i = 0; i < len; i++) {
A[l++] = s[i];
A[l++] = '#';
}
A[l] = 0;
int mx = 0, id = 0;
for (int i = 0; i < l; i++) {
B[i] = mx > i ? std::min(B[2 * id - i], mx - i) : 1;
while (A[i + B[i]] == A[i - B[i]]) B[i]++;
if (i + B[i] > mx) mx = i + B[i], id = i;
}
}
char A[MAXN * 2];
int B[MAXN * 2];
char str[MAXN];
int ren[MAXN], root[MAXN];
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%s", str + 1);
int n = strlen(str + 1);
Manacher(str + 1, n, A + 1, B + 1);
int maxR = 0;
for (int i = 1; i <= n; i++) ren[i] = (B[i * 2 + 1] - 2) >> 1, maxR = max(maxR, i - ren[i]);
tree.init();
root[0] = 0;
for (int i = 1; i <= n; i++) {
root[i] = tree.update(root[i - 1], i - ren[i], 1, 1, maxR);
}
ll res = 0;
for (int i = 1; i <= n; i++) {
if (ren[i] == 0) continue;
// printf("%d %d %d %d
", i, i, i+ren[i], tree.query(root[i], root[i+ren[i]], i, 1, maxR));
res = res + tree.query(root[i], root[i+ren[i]], i, 1, maxR);
}
printf("%lld
", res);
// for (int i = 1; i <= n; i++) {
// printf("%d ", ren[i]);
// }
// printf("
");
}
}