[TJOI2019]甲苯先生和大中锋的字符串
Description
给定模式串 s 和一个整数 k ,求所有出现次数为 k 次的字符串中长度出现次数最多的长度。
多测。
\(n \leq 10 ^ 5,\ \ \sum{n} \leq 3 \cdot 10 ^ 6\)
Solution
这些一看起来暴力就很劣的字符串可能多半和 SAM 有点关系。
而且这题个人感觉比较萌萌,主要是他让我们干的事全部写的明明白白。
所以说我们要先能知道那些字符串出现次数为 k ,维护 SAM 上状态的 siz 就可以了,那么对于每个状态如果满足条件,所有包含在这个长度里的字符串都有 1 的贡献,区间加,差分,最后统一统计。
Code
Code
/*
*/
#include
using namespace std;
typedef long long ll;
const int N = 6e6 + 10;
int k, arr[N];
inline int read() {
char ch = getchar();
int s = 0, w = 1;
while (!isdigit(ch)) {if (ch == '-') w = -1; ch = getchar();}
while (isdigit(ch)) {s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar();}
return s * w;
}
struct SAM {
int n, cnt, las, len[N], link[N], ch[N][26];
char s[N]; int tong[N], rk[N], siz[N];
inline void init() {cnt = las = 1; memset(ch[1], 0, sizeof(ch[1]));}
inline void SAM_stru(int c) {
int cur = ++cnt, p = las;
memset(ch[cur], 0, sizeof(ch[cur]));
las = cur;
len[cur] = len[p] + 1; siz[cur] = 1;
while (p && !ch[p][c]) ch[p][c] = cur, p = link[p];
if (!p) {link[cur] = 1; return ;}
int q = ch[p][c];
if (len[p] + 1 == len[q]) {link[cur] = q; return ;}
int clo = ++cnt;
link[clo] = link[q]; len[clo] = len[p] + 1;
link[q] = link[cur] = clo; siz[clo] = 0;
memcpy(ch[clo], ch[q], sizeof(ch[clo]));
while (p && ch[p][c] == q) ch[p][c] = clo, p = link[p];
}
inline void Tong_sort() {
for (int i = 1; i <= cnt; ++i) tong[i] = 0;
for (int i = 1; i <= cnt; ++i) ++tong[len[i]];
for (int i = 1; i <= cnt; ++i) tong[i] += tong[i - 1];
for (int i = 1; i <= cnt; ++i) rk[tong[len[i]]--] = i;
for (int i = cnt, u, v; i; --i) {
v = rk[i]; u = link[v];
siz[u] += siz[v];
if (siz[v] == k) ++arr[len[u] + 1], --arr[len[v] + 1];
}
}
} s;
inline void mian() {
s.init();
scanf("%s", s.s + 1); s.n = strlen(s.s + 1); k = read();
for (int i = 1; i <= s.n; ++i) s.SAM_stru(s.s[i] - 'a');
s.Tong_sort();
int mx = -1, ans = -1;
for (int i = 1; i <= s.n; ++i) {
arr[i] += arr[i - 1];
if (mx <= arr[i]) {
mx = arr[i]; ans = i;
}
}
printf("%d\n", (mx > 0) ? ans : -1);
for (int i = 1; i <= s.n + 1; ++i) arr[i] = 0;
}
int main() {
int t = read();
while (t--) mian();
return 0;
}

浙公网安备 33010602011771号