题意
- 给你一个字符串,问其所有子串的优秀拆分方案数之和,优秀拆分定义为S = AA + BB,其中A, B都是字符串。
我们发现只需要算每个位置作为AA串开头的方案数与每个串作为BB串结尾的方案数,然后相邻位置乘起来就可以了。
我们可以枚举AA串的长度 x x x,把整个序列下标为 x x x的倍数的位置标记为关键点,那么任何一个长度为 x x x的AA串它一定会跨过且仅跨过2个关键点,那么我们统计相邻两个关键点的后缀的LCP与前缀的LCS,那么我们把这个东西拼起来如果不小于 x x x,那么会贡献|LCS| + |LCP| - x + 1个开头和结尾,我们作一个区间加法,差分实现就好了,复杂度 O ( n log n ) O(\text{n log n}) O(n log n)。
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define mp make_pair
#define inf (0x3f3f3f3f)
#define mem(a, b) memset(a, b, sizeof(a))
#define Rep(i, a) for (int i = 0; i < a; ++ i)
#define For(i, a, b) for (int i = a; i <= b; ++ i)
#define Forr(i, a, b) for (int i = a; i >= b; -- i)
#define Travel(i, x) for (int i = head[x]; i; i = nxt[i])
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
template<class T>inline bool chkmax(T &_, T __) { return _ < __ ? _ = __, 1 : 0; }
template<class T>inline bool chkmin(T &_, T __) { return _ > __ ? _ = __, 1 : 0; }
inline void proStatus() {
ifstream t("/proc/self/status");
cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>());
}
const int N = 6e4 + 3;
char s[N];
int t, n, st[N], ed[N], lg[N];
struct Suffix_Array {
int SA[N], rk[N], height[N];
int tp[N], tong[N], st[17][N], m;
void Radix_Sort() {
For(i, 1, m) tong[i] = 0;
For(i, 1, n) ++ tong[rk[tp[i]]];
For(i, 1, m) tong[i] += tong[i - 1];
Forr(i, n, 1) SA[tong[rk[tp[i]]] --] = tp[i];
}
int query(int l, int r) {
l = rk[l], r = rk[r];
if (l > r) swap(l, r);
++ l;
int len = lg[r - l + 1];
return min(st[len][l], st[len][r - (1 << len) + 1]);
}
void build() {
mem(tp, 0), mem(rk, 0);
For(i, 1, n) chkmax(m, rk[i] = s[tp[i] = i]);
Radix_Sort();
for (int len = 1; len < n; len <<= 1) {
int cnt = 0;
For(i, n - len + 1, n) tp[++ cnt] = i;
For(i, 1, n) if (SA[i] > len) tp[++ cnt] = SA[i] - len;
Radix_Sort(), swap(rk, tp), rk[SA[1]] = m = 1;
For(i, 2, n) {
if (tp[SA[i]] ^ tp[SA[i - 1]] || tp[SA[i] + len] ^ tp[SA[i - 1] + len]) ++ m;
rk[SA[i]] = m;
}
if (m == n) break;
}
For(i, 1, n) {
int now = max(0, height[rk[i - 1]] - 1);
while (s[i + now] == s[SA[rk[i] - 1] + now]) ++ now;
st[0][rk[i]] = height[rk[i]] = now;
}
For(j, 1, 16) For(i, 1, n + 1 - (1 << j))
st[j][i] = min(st[j - 1][i], st[j - 1][i + (1 << (j - 1))]);
}
} SA1, SA2;
void update(int *a, int l, int r) { ++ a[l], -- a[r + 1]; }
int main() {
freopen("2083.in", "r", stdin);
freopen("2083.out", "w", stdout);
For(i, 2, N - 1) lg[i] = lg[i >> 1] + 1;
for (scanf("%d", &t); t -- ; mem(st, 0), mem(ed, 0)) {
scanf("%s", s + 1), n = strlen(s + 1);
SA1.build(), reverse(s + 1, s + n + 1), SA2.build();
For(i, 1, n >> 1) for (int j = i * 2; j <= n; j += i) {
int L = j - i, R = j, suf = SA1.query(L, R), pre = SA2.query(n - L + 1, n - R + 1);
chkmin(suf, i), chkmin(pre, i);
if (pre + suf >= i) {
int all = pre + suf - i + 1;
update(st, L - pre + 1, L - pre + all - 1);
update(ed, R + suf - all + 1, R + suf - 1);
}
}
For(i, 1, n) st[i] += st[i - 1], ed[i] += ed[i - 1];
ll ans = 0;
For(i, 2, n) ans += 1ll * ed[i - 1] * st[i];
cout << ans << endl;
}
return 0;
}