#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. replace all

    OPTION COPY OUTREC FINDREP=(INOUT=(X'0E',X'400E', X'0F',X'0F40'))

  2. JQuery--关系选择器

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. objectarx之遍历当前模型空间中的所有实体,并对每个实体进行炸开

    //炸开void BomEntity(){ AcDbBlockTable *pBlkTbl; acdbHostApplicationServices()->workingDatabase()-& ...

  4. windows.open window.location.href的用法和区别

    window.location.href  只能在当前页面打开,不能用新窗口打开 windows.open("URL","窗口名称","窗口外观设定& ...

  5. IDEA切换git分支

    查看当前所在分支 场景:在多人开发中,需要在主分支的基础上创建一些分支分配给小团队或个人去开发,然后小分支上的小功能开发完毕之后,再merge(合并)到主分支. 1.查看当前所在的分支 下图1.1中是 ...

  6. F4NNIU 整理的 docker-compose 几个常用命令

    F4NNIU 整理的 docker-compose 几个常用命令 up 创建并启动一个容器. 记录一下,如果已经有容器,up 和 start 都可以启动容器,up 可以看到调试窗口,但是 start ...

  7. ubuntu 使用glfw.h 出现函数无法调用

    最近在学习在Ubuntu下使用qt进行opengl开发,使用到了glfw这个库.我安装官网的编译和安装方法进行了配置安装,在usr/local/include的下产生了glfw.h文件. 于是我在我的 ...

  8. python生成器和各种推导式

    一. 生成器 本质就是迭代器. 一个一个的创建对象 创建生成器的方式: 1. 生成器函数 2. 通过生成器表达式来获取生成器 3. 类型转换(看不到) 二. 生成器函数 (重点) 生成器函数中包含 y ...

  9. Libev源码分析08:Libev中的内存扩容方法

    在Libev中,如果某种结构的数组需要扩容,它使用array_needsize宏进行处理,比如: array_needsize (int, fdchanges, fdchangemax, fdchan ...

  10. IP应用加速技术详解:如何提升动静混合站点的访问速率?

    全站加速(DCDN)-IPA是阿里云自主研发四层加速产品,它基于TCP/UDP的私有协议提供加速服务,包括解决跨运营商网络不稳定.单线源站.突发流量.网络拥塞等诸多因素导致的延迟高.服务不稳定的问题, ...