#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = ;
char s[maxn];
int sa[maxn], t[maxn], t2[maxn], c[maxn];
int n;
//构造字符串s的后缀数组, 每个字符值必须为0 ~ m-1
void build_sa(int m) {
int *x = t, *y = t2;
//基数排序
for(int i = ; i < m; i++) c[i] = ;
for(int i = ; i < n; i++) c[x[i] = s[i]]++;
for(int i = ; i < m; i++) c[i] += c[i-];
for(int i = n-; i >= ; i--) sa[--c[x[i]]] = i;
for(int k = ; k <= n; k <<= ) {
int p = ;
//直接利用sa数组排序第二关键字
for(int i = n-k; i < n; i++) y[p++] = i;
for(int i = ; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
//基数排序第一关键字
for(int i = ; i < m; i++) c[i] = ;
for(int i = ; i < n; i++) c[x[y[i]]]++;
for(int i = ; i < m; i++) c[i] += c[i-];
for(int i = n-; i>= ; i--) sa[--c[x[y[i]]]] = y[i];
//根据sa和y数组计算新的x数组
swap(x, y);
p = ;
x[sa[]] = ;
for(int i = ; i < n; i++)
x[sa[i]] = (y[sa[i-]] == y[sa[i]] && y[sa[i-]+k] == y[sa[i]+k] ? p- : p++);
if(p >= n) break;
m = p;
}
} int rank_[maxn]; //rank[i]代表后缀i在sa数组中的下标
int height[maxn]; //height[i] 定义为sa[i-1] 和 sa[i] 的最长公共前缀
//后缀j和k的LCP长度等于RMQ(height, rank[j]+1, rank[k])
void get_height() {
int i, j, k = ;
for(int i = ; i < n; i++) rank_[sa[i]] = i;
for(int i = ; i < n; i++) {
if(!rank_[i]) continue;
int j = sa[rank_[i]-];
if(k) k--; while(s[i+k] == s[j+k]) k++;
height[rank_[i]] = k;
}
}
int d[maxn][];
void rmq_init() {
for(int i = ; i < n; i++) d[i][] = height[i];
for(int j = ; (<<j) <= n; j++)
for(int i = ; i + (<<j) - < n; i++)
d[i][j] = min(d[i][j-], d[i+(<<(j-))][j-]);
}
int rmq(int l, int r) {
if(l == r) return n-l;
if(rank_[l] > rank_[r]) swap(l, r);
int L = rank_[l]+;
int R = rank_[r];
int k = ;
while((<<(k+)) <= R-L+) k++;
return min(d[L][k], d[R-(<<k)+][k]);
}
//LCP加速多模式匹配
int m;
int cmp_suffix(char* P, int p, int c,int &k) {
k = ;
int i;
for(i = ; P[c+i] == s[sa[p]+c+i]; i++) {
if(P[c+i] == '\0')
return ;
k++;
}
if(P[c+i] == '\0')
return ;
return P[c+i] - s[sa[p]+c+i];
}
vector<int> A;
void b_search(char*P, int L, int R) {
int k;
if(cmp_suffix(P, L, , k) < ) return ;
if(cmp_suffix(P, R, , k) > ) return ;
int c = , rr = ;
int lst = -;
k = ;
while(R >= L) {
int M = L + (R-L)/;
if(lst != -) c = rmq(lst, sa[M]);
if(c <= k) {
int res = cmp_suffix(P, M, c, k);
rr = res;
if(!res) {
A.push_back(sa[M]);
b_search(P, L, M-);
b_search(P, M+, R);
return;
}
lst = sa[M];
if(res < ) R = M-; else L = M+;
}
else if(rr < )R = M-;
else L = M+;
}
}
void find(char* P) { //找到全部的匹配位置存入A数组中
A.clear();
m = strlen(P);
int L = , R = n-;
b_search(P, L, R);
sort(A.begin(), A.end());
}

后缀数组 + LCP加速多模式匹配算法 O(m+logn)的更多相关文章

  1. poj 2774 Long Long Message 后缀数组LCP理解

    题目链接 题意:给两个长度不超过1e5的字符串,问两个字符串的连续公共子串最大长度为多少? 思路:两个字符串连接之后直接后缀数组+LCP,在height中找出max同时满足一左一右即可: #inclu ...

  2. hdu 3518 Boring counting 后缀数组LCP

    题目链接 题意:给定长度为n(n <= 1000)的只含小写字母的字符串,问字符串子串不重叠出现最少两次的不同子串个数; input: aaaa ababcabb aaaaaa # output ...

  3. hdu 4691 最长的共同前缀 后缀数组 +lcp+rmq

    http://acm.hdu.edu.cn/showproblem.php? pid=4691 去年夏天,更多的学校的种族称号.当时,没有后缀数组 今天将是,事实上,自己的后缀阵列组合rmq或到,但是 ...

  4. 后缀数组LCP + 二分 - UVa 11107 Life Forms

    Life Forms Problem's Link Mean: 给你n个串,让你找出出现次数大于n/2的最长公共子串.如果有多个,按字典序排列输出. analyse: 经典题. 直接二分判断答案. 判 ...

  5. UVA 11107 Life Forms——(多字符串的最长公共子序列,后缀数组+LCP)

    题意: 输入n个序列,求出一个最大长度的字符串,使得它在超过一半的DNA序列中连续出现.如果有多解,按照字典序从小到大输出所有解. 分析:这道题的关键是将多个字符串连接成一个串,方法是用不同的分隔符把 ...

  6. POJ2774 Long Long Message 【后缀数组lcp】

    长长的消息 时间限制: 4000MS   内存限制: 131072K 提交总数: 32393   接受: 13079 案件时间限制: 1000MS 描述 小猫在拜特兰的首府物理专业.最近有一个不幸的消 ...

  7. 【BZOJ】1692 & 1640: [Usaco2007 Dec]队列变换(后缀数组+贪心)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1692 http://www.lydsy.com/JudgeOnline/problem.php?id ...

  8. bzoj 4278 Tasowanie 后缀数组+贪心

    题目大意 给定两个数字串A和B,通过将A和B进行二路归并得到一个新的数字串T,请找到字典序最小的T.\(len \leq 200000\) 题解 我们从归并排序的角度去想,每次把两者之一较小的取出来 ...

  9. poj 3261 后缀数组 找反复出现k次的子串(子串能够重叠)

    题目:http://poj.org/problem?id=3261 仍然是后缀数组的典型应用----后缀数组+lcp+二分 做的蛮顺的,1A 可是大部分时间是在调试代码.由于模板的全局变量用混了,而自 ...

随机推荐

  1. PHP开发api接口安全验证的实例,值得一看

    php的api接口 在实际工作中,使用PHP写api接口是经常做的,PHP写好接口后,前台就可以通过链接获取接口提供的数据,而返回的数据一般分为两种情况,xml和json,在这个过程中,服务器并不知道 ...

  2. man命令及help命令

    一.man命令 man命令常用工具命令 man命令是Linux下的帮助指令,通过man指令可以查看Linux中的指令帮助.配置文件帮助和编程帮助等信息. 语法: man(选项)(参数) 选项: -a: ...

  3. win10下Anaconda3配置环境变量

    有时候在win10安装好Anaconda3后,使用conda命令时依然会出现: C:\Users\dell\PycharmProjects\pytorch>conda list 'conda' ...

  4. UVa 926【简单dp,递推】

    UVa 926 题意:给定N*N的街道图和起始点,有些街道不能走,问从起点到终点有多少种走法. 很基础的dp.递推,但是有两个地方需要注意,在标记当前点某个方向不能走时,也要同时标记对应方向上的对应点 ...

  5. 防止chrome主页被篡改并设置为默认打开无痕浏览方式

    1. 找到chrome的快捷方式, 右击打开属性 2. 将目标框内容改为以下内容chrome.exe的目录位置 // ----- 引号中的内容为"PATH\Chrome\Applicatio ...

  6. C++ 求向量的交集、并集、差集

    #include<iostream> #include<stdio.h> #include<list> #include<algorithm> //se ...

  7. java基础-内存分配

    1.java运行时的数据区:程序计数器.方法区.虚拟机栈.本地方法栈.堆 ①.程序计数器:一块较小的内存空间,可看作当前线程所执行的字节码的行号指示器 ②.java虚拟机栈:与程序计数器一样,也是线程 ...

  8. Python基础:25文件

    一:文件对象 文件对象不仅可以用来访问普通的磁盘文件, 而且也可以访问任何其它类型抽象层面上的"文件". 一旦设置了合适的"钩子", 你就可以访问具有文件类型接 ...

  9. @loj - 3022@ 「CQOI2017」老 C 的方块

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 老 C 是个程序员. 作为一个懒惰的程序员,老 C 经常在电脑上 ...

  10. dev stg prd 开发 测试 生产环境

    dev development 开发环境stg stage 测试环境prd product 线上环境