http://blog.csdn.net/gatevin/article/details/45875343

题目是求不重叠的不同子串个数

一般来说,

endpos集合包含了子串结尾位置,结尾在"3、4、6"等

每个状态都包含了若干个连续子串。就是"aabab", "abbab", "bbab", "bab"属于同一个状态

endpos集合的大小就是这些子串的出现次数

但是这样会重叠。那么可以求出endpos结合的结尾最小值,和结尾最大值。

那么长度小于mx - mi的子串,是肯定不会重叠的

至于有多少个,可以由mxcnt决定

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = + , N = ;
struct Node {
int mxCnt; //mxCnt表示后缀自动机中当前节点识别子串的最大长度
int miCnt; //miCnt表示后缀自动机中当前节点识别子串的最小长度
int id; //表示它是第几个后缀自动机节点,指向了它,但是不知道是第几个,用id判断
int mxPos, miPos; //pos表示它在原串中的位置。
bool flag; //表示当前节点是否能识别前缀
struct Node *pNext[N], *fa;
}suffixAutomaton[maxn * ], *root, *last; //大小需要开2倍,因为有一些虚拟节点
int t; //用到第几个节点
struct Node *create(int mxCnt = -, struct Node *node = NULL) { //新的节点
if (mxCnt != -) {
suffixAutomaton[t].mxCnt = mxCnt, suffixAutomaton[t].fa = NULL;
for (int i = ; i < N; ++i) suffixAutomaton[t].pNext[i] = NULL;
} else {
suffixAutomaton[t] = *node; //保留了node节点所有的指向信息。★全部等于node
//可能需要注意下pos,在原串中的位置。现在pos等于原来node的pos
}
suffixAutomaton[t].id = t; //必须要有的,不然id错误
suffixAutomaton[t].flag = false; //默认不是前缀节点
return &suffixAutomaton[t++];
}
void addChar(int x, int pos) { //pos表示在原串的位置
struct Node *p = last, *np = create(p->mxCnt + , NULL);
np->flag = true;
np->mxPos = np->miPos = pos, last = np; //last是最尾那个可接收后缀字符的点。
for (; p != NULL && p->pNext[x] == NULL; p = p->fa) p->pNext[x] = np;
if (p == NULL) {
np->fa = root;
np->miCnt = ; // 从根节点引一条边过来
return;
}
struct Node *q = p->pNext[x];
if (q->mxCnt == p->mxCnt + ) { //中间没有任何字符,可以用来代替接受后缀、
np->fa = q;
np->miCnt = q->mxCnt + ; // q是状态8的"ab",np是状态7的"bab"长度是2+1
return;
}
// p: 当前往上爬到的可以接受后缀的节点
// np:当前插入字符x的新节点
// q: q = p->pNext[x],q就是p中指向的x字符的节点
// nq:因为q->cnt != p->cnt + 1而新建出来的模拟q的节点
struct Node *nq = create(-, q); // 新的q节点,用来代替q,帮助np接收后缀字符
nq->mxCnt = p->mxCnt + ; //就是需要这样,这样中间不包含任何字符
q->miCnt = nq->mxCnt + , np->miCnt = nq->mxCnt + ;
q->fa = nq, np->fa = nq; //现在nq是包含了本来q的所有指向信息
for (; p && p->pNext[x] == q; p = p->fa) {
p->pNext[x] = nq;
}
}
void init() {
t = ;
root = last = create(, NULL);
}
void build(char str[], int lenstr) {
init();
for (int i = ; i <= lenstr; ++i) addChar(str[i] - 'a', i);
}
char str[maxn];
queue<int> que;
int dp[maxn * ], in[maxn * ];
void work() {
scanf("%s", str + );
build(str, strlen(str + ));
for (int i = ; i < t; ++i) {
in[suffixAutomaton[i].fa->id]++;
}
for (int i = ; i < t; ++i) {
if (in[i] == ) que.push(i);
}
while (!que.empty()) {
int cur = que.front();
que.pop();
if (!cur) break;
int fa = suffixAutomaton[cur].fa->id;
suffixAutomaton[fa].mxPos = max(suffixAutomaton[fa].mxPos, suffixAutomaton[cur].mxPos);
in[fa]--;
if (in[fa] == ) que.push(fa);
}
LL ans = ;
for (int i = ; i < t; ++i) {
int dis = suffixAutomaton[i].mxPos - suffixAutomaton[i].miPos;
int mi = min(suffixAutomaton[i].mxCnt, dis);
if (dis < suffixAutomaton[i].miCnt) continue;
ans += mi - suffixAutomaton[i].miCnt + ;
}
printf("%lld\n", ans);
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
work();
return ;
}

SETI ACdream - 1430 后缀自动机求不相交子串的更多相关文章

  1. str2int HDU - 4436 后缀自动机求子串信息

    题意: 给出 n 个串,求出这 n 个串所有子串代表的数字的和. 题解; 首先可以把这些串构建后缀自动机(sam.last=1就好了), 因为后缀自动机上从 root走到的任意节点都是一个子串,所有可 ...

  2. BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串

    http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...

  3. 洛谷P4248 [AHOI2013]差异(后缀自动机求lcp之和)

    题目见此 题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的 ...

  4. Alice's Classified Message HDU - 5558 后缀自动机求某个后缀出现的最早位置

    题意: 给定一个长度不超过 10W 的只包含小写字母的字符串,从下标 0 到 n−1.从下标 0 开始操作, 每次对于下标 pos查找下标 pos 开始的子串中最长的在其他地方出现过的长度,其他出现的 ...

  5. 后缀自动机求字典序第k小的串——p3975

    又领悟到了一点新的东西,后缀自动机其实可以分为两个数据结构,一个是后缀树,还有一个是自动机 后缀树用来划分endpos集合,并且维护后缀之间的关系,此时每个结点代表的是一些后缀相同且长度连续的子串 自 ...

  6. JDOJ 2939: Suffix Automaton 广义后缀自动机_统计子串

    建立广义后缀自动机,对每个节点都建立各自的 $Parent$ 数组. 这样方便统计,不会出现统计错误. 考虑新加入一个字符. 1 这条转移边已经存在,显然对答案没有贡献. 2 这条转移边不存在,贡献即 ...

  7. CodeForces-204E:Little Elephant and Strings (广义后缀自动机求出现次数)

    The Little Elephant loves strings very much. He has an array a from n strings, consisting of lowerca ...

  8. 洛谷 P1368 工艺 后缀自动机 求最小表示

    后缀自动机沙茶题 将字符串复制一次,建立后缀自动机. 在后缀自动机上贪心走 $n$ 次即可. Code: #include <cstdio> #include <algorithm& ...

  9. 后缀自动机模板——不同子串个数p2408

    后缀自动机的入门博客 https://www.luogu.org/blog/Kesdiael3/hou-zhui-zi-dong-ji-yang-xie 有两种求法,分别对应了两种性质 #includ ...

随机推荐

  1. JMeter上传文件 点选form-data依旧失败的解决方法

    转子:https://blog.csdn.net/xingyunpi/article/details/77930476 这几天一直在调用JMeter上传文件的一个接口,一直出错,在网上找到一些文章说的 ...

  2. TestNG入门

    在Eclipse中安装TestNG 打开Eclipse   Help ->Install New Software ,   然后Add   "http://beust.com/ecli ...

  3. c# get set 理解

  4. 基于Ace Admin 的菜单栏实现

    1.首先是数据库表必然包含以下几个字段Id ,ParnetId,Url,Name等 create table dbo.Module ( Id uniqueidentifier not null con ...

  5. 微信开放平台 redirect_uri参数错误

    微信开放平台 redirect_uri参数错误   请注意是开放平台开放平台,公众平台和开放平台不是同一个. 解决办法 在写 授权回调域 时,地址只用写到域名级,不能写到域名下一级,这和QQ互联的回调 ...

  6. linux虚拟机与windows主机传输文件方法

    通过ssh    这种方法需要虚拟机内的linux安装ssh服务,默认是安装的。 首先检查ssh服务是开启的,通过shell下执行命令:service ssh status, 查看ssh服务是否已开启 ...

  7. 浅谈UBUNTU

    一 UBUNTU介绍 Ubuntu(乌班图)是一个以桌面应用为主的Linux操作系统,其名称来自非洲南部祖鲁语或豪萨语的"ubuntu"一词,意思是"人性".& ...

  8. 手把手教你如何制作和使用lib和dll_转载

    目录 静态库 什么是静态库? 怎么创建 如何使用 静态库的第一种使用方法 静态库的第二种使用方法 动态链接库 动态库是什么? 怎么创建 如何使用 隐式调用 显式调用 静态库什么是静态库?我们先来说一下 ...

  9. 乱序优化与GCC的bug

      以下内容来自搜狗实验室技术交流文档,搜狐公司研发中心版权所有,仅供技术交流   摘要 --------- 乱序优化是现代编译器非常重要的特性,本文介绍了什么是乱序优化,以及由此引发的一个bug,希 ...

  10. VisualStudio.Net应用程序制作图标

    前段时间用到了VS自带打包工具,对程序进行打包,但是由于打包完成后,安装后的软件图标甚是难看于是想把图标也给打包进去.于是找到了两个解决方式. 第一种也是最简单的: 在VS中按照下面方式进行即可: 第 ...