当前位置: 首页 > news >正文

【题解】洛谷 P4081 [USACO17DEC] Standing Out from the Herd P [后缀自动机 SAM]

没学过指路:【详细注释 | 字符串算法集合 2】后缀自动机 SAM & 后缀数组 SA-CSDN博客


P4081 [USACO17DEC] Standing Out from the Herd P - 洛谷 (luogu.com.cn)

广义后缀自动机 SAM 解法

和普通 SAM 的唯一区别就是每个串开始前 np = 1,

不在上一个字串的后面接,就和 AC 自动机 p = 0 差不多。

np = 1 其实 ch 数组和 fa 数组没什么大的区别,不同字符串同样的后缀照样可以链接

(这里可以去看洛谷上第一篇题解的图片,上一个字符串的字符通过根节点照样可以走到)

跑完 SAM 后,遍历每个串下标节点的 fa 一条链。

(为什么是下标节点?因为只有下标节点的结束位置才不相同,才是真正的互不相同的后缀)

定义 v 数组初始化为 0,v[i] 代表节点 i 属于哪个串,为 -1 时代表节点 i 同时属于很多串。

如果这个节点的 v  = 0 则 v = 当前字符串编号,反之 v 已经有了别的就 v[i] = -1。

(遍历整条 fa 链,有可能到不同字符串的节点,这些节点代表相同的后缀,也就是重复子串)

最后再次遍历所有节点,统计答案 ans[当前字符串编号] = len[i] - len[fa[i]],

因为 fa 指向的是和 i 有最长公共后缀的且不同结束位置节点

两者 len 的差正好就是以 i 为结尾但从没出现过的子串。

还有些细节写代码注释里了:

#include<bits/stdc++.h>
using namespace std;typedef long long LL;
const int N = 2e5 + 10;char s[N], ss[N];
int np, tot;
int len[N], v[N], slen[N];
int ch[N][30], fa[N];
LL ans[N];void extend(int c) {int p = np;tot ++;np = tot;len[np] = len[p] + 1;for (; p && !ch[p][c]; p = fa[p]) {ch[p][c] = np;}if (!p) {fa[np] = 1;}else {int r = ch[p][c];if (len[r] == len[p] + 1) {fa[np] = r;}else {tot ++;int nr = tot;len[nr] = len[p] + 1;fa[nr] = fa[r];fa[r] = nr;fa[np] = nr;for (; p && ch[p][c] == r; p = fa[p]) {ch[p][c] = nr;} memcpy(ch[nr], ch[r], sizeof(ch[r]));}}
} void get_v(int x, int i) {for (; x && v[x] != i && v[x] != -1; x = fa[x]) {   // 遇到 v[x] 不是当前字符串,那么 x 的后缀也不是当前字符串,直接退出就好 if (v[x] != 0) {v[x] = -1;}else {v[x] = i;}}
}int main () {ios::sync_with_stdio(false);cin.tie(0);tot = np = 1;fa[1] = 0;memset(len, 0, sizeof(len));memset(v, 0, sizeof(v));memset(ch, 0, sizeof(ch));int n, sl = 0;cin >> n;for (int i = 1; i <= n; i ++) {np = 1;cin >> ss + 1;slen[i] = strlen(ss + 1);for (int j = 1; ss[j]; j ++) {   // 神人出题人,搞得读入像坨 s[sl + j] = ss[j];extend(ss[j] - 'a');}sl += slen[i];}int x = 1, last = 0;for (int i = 1; i <= n; i ++) {x = 1;for (int j = 1; j <= slen[i]; j ++) {x = ch[x][s[last + j] - 'a'];get_v(x, i);}last += slen[i];}memset(ans, 0, sizeof(ans));for (int i = 1; i <= tot; i ++) if (v[i] != -1) {ans[v[i]] += (len[i] - len[fa[i]]);}for (int i = 1; i <= n; i ++) {cout << ans[i] << "\n";}return 0;
} 

http://www.dtcms.com/a/427660.html

相关文章:

  • 专做立体化的网站赣州君拓网络科技有限公司
  • 网站开发2019企业微信营销系统
  • Linux磁盘挂载脚本
  • nuttx实战项目:多路串口合并功能之六nuttx项目基本优化
  • mysql语句之insert语句DML事务的结束
  • 单机 6 节点打造Redis Cluster(3主3从)——从零到可用与踩坑速修
  • Cesium快速入门到精通系列教程二十:Cesium 1.95 给实体添加事件
  • 02、命令行的介绍
  • 三五互联网站管理登录地址wordpress 黑色
  • 小杰深度学习(four)——神经网络可解释性、欠拟合、过拟合
  • 【手撕机器学习 03】从“生数据”到“黄金特征”:机器学习项目中价值最高的一步
  • 网站关键字优化教程株洲发布信息网
  • 昆明优化网站公司在与客户谈网页广告时如何让客户相信网站流量
  • UNIX下C语言编程与实践21-UNIX 文件访问权限控制:st_mode 与权限宏的解析与应用
  • 瑞芯微RK35XX系列FFmpeg硬件编解码实测,详细性能对比!
  • php网站后台搭建wordpress购买返现
  • 首架机下线!“四川造”大型载客eVTOL筑低空新里程碑
  • 基于STM32与influxDB的电力监控系统-13
  • 250925-0930技术总结
  • AI 重塑实体经济:从技术落地到价值创造的实践路径
  • 认识软件测试
  • 网站服务器数据库湛江网站建设公司哪个好
  • 动手实现简单Vue.js ,探索Vue原理
  • UNIX下C语言编程与实践18-UNIX 文件存储原理:目录、i 节点、数据块协同存储文件的过程
  • 珠宝怎么做网站wordpress 活动报名插件
  • 除自身以外数组的乘积
  • 爬虫逆向--Day25Day26--原型链补环境
  • 拍拍灯电路(用咪头识别拍拍动作)
  • 极限!ubuntu系统联网
  • 第三章 字典与集合