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. [译]Javascript基础

    本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...

  2. STL 堆的使用

    本来是要写leetcode上的merge k sorted lists那道题目,这个题目我还是很熟悉的,毕竟是看过算法导论的人,但是写的过程中对堆的维护代码还是挺多的,所以我想到了STL中的堆.下面就 ...

  3. Spring中的事务控制

    Spring中事务控制的API介绍 PlatformTransactionManager 此接口是spring的事务管理器,它里面提供了我们常用的操作事务的方法 我们在开发中都是使用它的实现类: 真正 ...

  4. [Study notes] To programing RGBD-SLAM together from Gaoxiang

    Solve CMake Error in CMakeLists.txt (FIND_PAKAGE): CMake Error at src/CMakeLists.txt:5 (FIND_PACKAGE ...

  5. Educational Codeforces Round 60 (Rated for Div. 2)E(思维,哈希,字符串,交互)

    #include <bits/stdc++.h>using namespace std;int main(){ string t; cin>>t; int n=t.size() ...

  6. c++语言的学习笔记代码与笔记注释《面向对象部分》

    #include <iostream> /*这是C++中关于面向对象部分的具体笔记和代码 */ //定义类的语法形式; //类中的成员项目之间相互引用,直接使用成员; //类外引用成员的时 ...

  7. 新姿势!Redis中调用Lua脚本以实现原子性操作

    背景:有一服务提供者Leader,有多个消息订阅者Workers.Leader是一个排队程序,维护了一个用户队列,当某个资源空闲下来并被分配至队列中的用户时,Leader会向订阅者推送消息(消息带有唯 ...

  8. 关于如何在Windows下测交互题

    这里的交互题指的NOI风格的交互题,即交互库 codeforces风格的交互题...只能自己实现评测插件了 使用Cena,Lemon没有附加文件功能不能评测交互题 在编译选项g++编译命令源文件中加入 ...

  9. Jenkins 相关

    手动下载Jenkins plugin 的地址, 下载后的是zip 文件,然后再手动修改为.hpi 文件,然后再手动上传 https://plugins.jenkins.io/

  10. kuangbin专题十六 KMP&&扩展KMP HDU3294 Girls' research

    One day, sailormoon girls are so delighted that they intend to research about palindromic strings. O ...