[hdu4416 Good Article Good sentence]后缀自动机SAM
题意:给出串A和串集合B={B1,B2,...,Bn},求串A的所有不同子串中不是B中任一串的子串的数目。
思路:把A和B中所有字符串依次拼接在一起,然后构造后缀自动机,计算每个状态的R集合元素的最大值r,然后统计那些r≤length(A)的状态。hdu不卡时间卡空间,这是最郁闷的。。。导致下面的程序只在本地随机数据没发现错误,提交就MLE。
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define pb(x) push_back(x)
#define mp(x, y) make_pair(x, y)
#define all(a) (a).begin(), (a).end()
#define mset(a, x) memset(a, x, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(b))
#define cas() int T, cas = 0; cin >> T; while (T --)
template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
typedef long long ll;
typedef pair<int, int> pii; #ifndef ONLINE_JUDGE
#include "local.h"
#endif const int N = 6e5 + 7; int len; //注意空间为 DOUBLE SIZE
class SAM {
public:
void init() {
memset(node, 0, sizeof(node));
sz = last = 0;
node[0].len = 0;
node[0].link = -1;
sz ++;
}
void add(char c) {
int cur = sz ++;
node[cur].len = node[last].len + 1;
node[cur].r = node[cur].len;
int p;
for (p = last; ~p && !node[p].next[c]; p = node[p].link) {
node[p].next[c] = cur;
}
if (p == -1) node[cur].link = 0;
else {
int q = node[p].next[c];
if (node[p].len + 1 == node[q].len) node[cur].link = q;
else {
int clone = sz ++;
node[clone].link = node[q].link;
memcpy(node[clone].next, node[q].next, sizeof(node[q].next));
node[clone].len = node[p].len + 1;
for (; ~p && node[p].next[c] == q; p = node[p].link) {
node[p].next[c] = clone;
}
node[q].link = node[cur].link = clone;
}
}
last = cur;
}
int c[N], p[N];
ll getAns() {
mset(c, 0);
for (int i = 0; i < sz; i ++) c[node[i].len] ++;
for (int i = 1; i <= sz; i ++) c[i] += c[i - 1];
for (int i = 0; i < sz; i ++) p[-- c[node[i].len]] = i;
for (int i = sz - 1; i >= 0; i --) {
int cur = p[i];
if (cur == 0) continue;
umax(node[node[cur].link].r, node[cur].r);
}
ll ans = 0;
for (int i = 1; i < sz; i ++) {
if (node[i].r <= len) ans += node[i].len - node[node[i].link].len;
}
return ans;
}
private:
const static int SZ = 27;
struct State {
int len, link;
int r;
int next[SZ];
};
State node[N];
int sz, last;
};
SAM sam;
char s[N]; int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
int n;
cas() {
cin >> n;
sam.init();
for (int i = -1; i < n; i ++) {
scanf("%s", s);
if (i < 0) len = strlen(s);
for (int j = 0; s[j]; j ++) {
sam.add(s[j] - 'a');
}
sam.add(26);
}
printf("Case %d: %I64d\n", ++ cas, sam.getAns());
}
return 0;
}
[hdu4416 Good Article Good sentence]后缀自动机SAM的更多相关文章
- 【算法】后缀自动机(SAM) 初探
[自动机] 有限状态自动机的功能是识别字符串,自动机A能识别字符串S,就记为$A(S)$=true,否则$A(S)$=false. 自动机由$alpha$(字符集),$state$(状态集合),$in ...
- [转]后缀自动机(SAM)
原文地址:http://blog.sina.com.cn/s/blog_8fcd775901019mi4.html 感觉自己看这个终于觉得能看懂了!也能感受到后缀自动机究竟是一种怎样进行的数据结构了. ...
- SPOJ 1811. Longest Common Substring (LCS,两个字符串的最长公共子串, 后缀自动机SAM)
1811. Longest Common Substring Problem code: LCS A string is finite sequence of characters over a no ...
- 后缀自动机SAM学习笔记
前言(2019.1.6) 已经是二周目了呢... 之前还是有一些东西没有理解到位 重新写一下吧 后缀自动机的一些基本概念 参考资料和例子 from hihocoder DZYO神仙翻译的神仙论文 简而 ...
- 浅谈后缀自动机SAM
一下是蒟蒻的个人想法,并不很严谨,仅供参考,如有缺误,敬请提出 参考资料: 陈立杰原版课件 litble 某大神 某大神 其实课件讲得最详实了 有限状态自动机 我们要学后缀自动机,我们先来了解一下自动 ...
- 后缀自动机(SAM)奶妈式教程
后缀自动机(SAM) 为了方便,我们做出如下约定: "后缀自动机" (Suffix Automaton) 在后文中简称为 SAM . 记 \(|S|\) 为字符串 \(S\) 的长 ...
- 后缀自动机SAM BZOJ 2806
终于遇到了一道后缀数组不能过 一定要学SAM的题... (看了半个下午+半个上午) 现在总结一下(是给我自己总结..所以只总结了我觉得重要的 .. 看不太懂的话可以To http://blog.c ...
- 【算法】后缀自动机(SAM) 例题
算法介绍见:http://www.cnblogs.com/Sakits/p/8232402.html 广义SAM资料:https://www.cnblogs.com/phile/p/4511571.h ...
- 后缀自动机(SAM)速成手册!
正好写这个博客和我的某个别的需求重合了...我就来讲一讲SAM啦qwq 后缀自动机,也就是SAM,是一种极其有用的处理字符串的数据结构,可以用于处理几乎任何有关于子串的问题,但以学起来异常困难著称(在 ...
随机推荐
- PHP Curl 请求https 60错误解决办法
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
- Linux学习笔记(三)目录和文件都能操作的命令
目录和文件都能操作的命令 rm cp mv rm 英文原意:remove files or directories 功能:删除文件或目录 语法:rm 选项[-fir] 文件或目录 rm -f 强制删除 ...
- mysql参数max_binlog_cache_size设置不当引发的血案
日常运维中的坑真是防不胜防,不一小心就遇到别人给你挖的坑.最近又遇到经验不足的DBA不知道从哪拷贝的配置文件(据说是当时参加某培训机构视频培训是资料里的模板,真的是误人子弟呀),其中把max_binl ...
- Java面试系列第2篇-Object类中的方法
Java的Object是所有引用类型的父类,定义的方法按照用途可以分为以下几种: (1)构造函数 (2)hashCode() 和 equals() 函数用来判断对象是否相同 (3)wait().wai ...
- Spark SQL源码解析(三)Analysis阶段分析
Spark SQL原理解析前言: Spark SQL源码剖析(一)SQL解析框架Catalyst流程概述 Spark SQL源码解析(二)Antlr4解析Sql并生成树 Analysis阶段概述 首先 ...
- 负载均衡服务之HAProxy基础配置(五)
前文我们聊了下haproxy的修改报文首部的配置.压缩功能以及haproxy基于http协议自定义健康状态检测机制:回顾请参考https://www.cnblogs.com/qiuhom-1874/p ...
- MySQL主从数据库配置与原理
1.为什么要搭建主从数据库 (1)通过增加从库实现读写分离,提高系统负载能力 (2)将从库作为数据库备份库,实现数据热备份,为数据恢复提供机会 (3)根据业务将不同服务部署在不同机器同时又共享相同的数 ...
- C#多线程(15):任务基础③
目录 TaskAwaiter 延续的另一种方法 另一种创建任务的方法 实现一个支持同步和异步任务的类型 Task.FromCanceled() 如何在内部取消任务 Yield 关键字 补充知识点 任务 ...
- 2019-2020-1 20199303《Linux内核原理与分析》第七周作业
进程的描述 1.进程概念 进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位.进程由程序段.数据段.PCB组成 2.PCB中的信息 ①进程标识符 ②处理机状态 ③进程调度信息 ④进程控制 ...
- linux sort 命令实用手册
Linux 中的sort 命令是一个很实用的工具,用于对文本内容以行为单位进行ASCII 码排序,默认按照升序进行排序(当然也可以按照降序). sort 命令的格式如下: sort `参数` `文件名 ...