Illublog我多想说再见啊

[TJOI2019]甲苯先生和大中锋的字符串

Illu·2022-03-13 10:12·33 次阅读

[TJOI2019]甲苯先生和大中锋的字符串

Description#

给定模式串 s 和一个整数 k ,求所有出现次数为 k 次的字符串中长度出现次数最多的长度。

多测。

n105,  n3106

Solution#

这些一看起来暴力就很劣的字符串可能多半和 SAM 有点关系。

而且这题个人感觉比较萌萌,主要是他让我们干的事全部写的明明白白。

所以说我们要先能知道那些字符串出现次数为 k ,维护 SAM 上状态的 siz 就可以了,那么对于每个状态如果满足条件,所有包含在这个长度里的字符串都有 1 的贡献,区间加,差分,最后统一统计。

Code#

Code
Copy
/* */ #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; }
posted @   Illusory_dimes  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
目录