这里介绍一种失了智的算法。
这种算法基于插桩原理。我们每隔len插一个庄,我们发现所有长度为len的子串都会和一个桩相交。然后对于每个长度len我们只要能够通过n/lenlog(len)的复杂度算出所有长度为len的SAN值就可以在nloglog的时间复杂度内解决问题。
这里有三个子问题:
1.如何判断[l1,r1]和[l2,r2]这两个子串是否相等,这里采用字符串哈希O(n)预处理 O(单次取模)查询。
2.如何判断过当前桩的所有子串和过前一个桩的子串有递增SAN值的关系,这里采用二分加哈希的方式来解决O(n)预处理 O(log*单次取模)的复杂度,也可以采用两次后缀数组的方式O(nlog)预处理 O(1)查询会更快一些。
3.如何处理长度为len的子串中某些san值递增,某些san值清零的问题。线段树O(log)处理
即使如此,你仍然无法通过此题,因为整体复杂度是O(nloglog*单次取模复杂度),%运算符是O(log)的,但是如今有取模黑科技可以比%运算符更加迅速,如此可以通过此题。
反正只要胆子大,常数卡卡就过了。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define lson rt * 2
#define rson rt * 2 + 1
typedef long long ll;
const int N = 1e5 + 100;
const int MOD = 1e9 + 7;
const int SZ = 200;
typedef unsigned long long ull;
typedef __uint128_t L;
struct FastMod {
ull b, m;
FastMod(ull b) : b(b), m(ull((L(1) << 64) / b)) {}
ull reduce(ull a) {
return a - (ull)((L(m) * a) >> 64) * b;
}
}F(MOD);
int tree[N * 4], laz[N * 4], flag[N * 4];
void push_down(int rt) {
if (flag[rt]) {
tree[lson] = laz[lson] = tree[rson] = laz[rson] = 0;
flag[lson] = flag[rson] = 1;
flag[rt] = 0;
}
laz[lson] += laz[rt];
tree[lson] += laz[rt];
laz[rson] += laz[rt];
tree[rson] += laz[rt];
laz[rt] = 0;
}
void insert(int rl, int rr, int l, int r, int rt) {
if (rl == l && rr == r) {
tree[rt]++;
laz[rt]++;
return;
}
push_down(rt);
int m = (l + r) / 2;
if (rr <= m) insert(rl, rr, l, m, lson);
else if (m < rl) insert(rl, rr, m + 1, r, rson);
else {
insert(rl, m, l, m, lson);
insert(m + 1, rr, m + 1, r, rson);
}
tree[rt] = max(tree[lson], tree[rson]) + laz[rt];
}
void clr(int rl, int rr, int l, int r, int rt) {
if (rl == l && rr == r) {
tree[rt] = laz[rt] = 0;
flag[rt] = 1;
return;
}
push_down(rt);
int m = (l + r) / 2;
if (rr <= m) clr(rl, rr, l, m, lson);
else if (m < rl) clr(rl, rr, m + 1, r, rson);
else {
clr(rl, m, l, m, lson);
clr(m + 1, rr, m + 1, r, rson);
}
tree[rt] = max(tree[lson], tree[rson]) + laz[rt];
}
int n;
char str[N];
ll pre[N], rff[N];
int qpow(int x, int n) {
int r = 1;
while (n > 0) {
if (n & 1) r = 1LL * r * x % MOD;
n /= 2;
x = 1LL * x * x % MOD;
}
return r;
}
void init() {
ll t = 1;
for (int i = 1; i <= n; i++) {
pre[i] = (pre[i - 1] + t * (str[i] - 'a')) % MOD;
t = t * 26 % MOD;
}
int r = qpow(26, MOD - 2);
rff[0] = 1;
for (int i = 1; i <= n; i++) rff[i] = 1LL * rff[i - 1] * r % MOD;
}
/*int get(int l, int r) {
if (r > n) return -1;
int ans = 1LL * (pre[r] - pre[l - 1]) * rff[l - 1] % MOD;
if (ans < 0) ans += MOD;
return ans;
}*/
int get(int l, int r) {
if (r > n) return -1;
int ans = F.reduce(F.reduce(pre[r] - pre[l - 1] + MOD) * rff[l - 1]);
if (ans >= MOD) ans -= MOD;
//printf("%d %d %d\n", l, r, ans);
return ans;
}
void upd(int &x, int y) {
if (y > x) x = y;
}
bool check(int l, int r, int d) {
return get(l, r) == get(l + d, r + d);
}
int q1(int ql, int qr, int len) {
if (str[ql] != str[ql - len]) return ql - 1;
int m, l = ql, r = qr;
while (r - l > 1) {
m = (l + r) / 2;
if (check(ql, m, -len)) l = m;
else r = m;
}
if (check(ql, r, -len)) return r;
return l;
}
int q2(int ql, int qr, int len) {
if (str[qr] != str[qr - len]) return 1e9;
int m, l = ql, r = qr;
while (l < r) {
m = (l + r) / 2;
if (check(m, qr, -len)) r = m;
else l = m + 1;
}
return l;
}
int main() {
//freopen("0.txt", "r", stdin);
int T;
scanf("%d", &T);
while (T--) {
scanf("%s", str + 1);
n = strlen(str + 1);
init();
int ans = 0;
for (int ma = 1; ma <= SZ && ma <= n; ma++) {
for (int i = 1; i <= ma; i++) {
int res = 1;
for (int j = i; j <= n; j += ma) {
if (j - ma >= 1 && get(j - ma, j - 1) == get(j, j + ma - 1)) res++;
else {
upd(ans, res);
res = 1;
}
}
upd(ans, res);
}
}
for (int sz = SZ + 1; sz <= n; sz++) {
clr(1, sz, 1, sz, 1);
for (int i = 2 * sz; i <= n; i += sz) {
int l = q2(i - sz + 1, i, sz) - i + sz, r = q1(i, i + sz - 1, sz) - i + 1;
if (r < l) {
clr(1, sz, 1, sz, 1);
}
else {
if (l > 1) clr(1, l - 1, 1, sz, 1);
if (r < sz) clr(r + 1, sz, 1, sz, 1);
insert(l, r, 1, sz, 1);
}
upd(ans, tree[1] + 1);
}
}
printf("%d\n", ans);
}
return 0;
}
京公网安备 11010502036488号