后缀数组解决在线的多模板匹配问题

终于学会倍增法了, 先一个最水最水的后缀数组应用。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn = 1e6;

char buf[maxn];
int str[maxn], len, sa[maxn];

inline int idx(char c) {
	return c - ‘a‘;
}

int stra[maxn], strb[maxn], strcnt[maxn];

void build_sa(int *str, int *sa, int n, int m) {
	int i, j, *x = stra, *y = strb, *cnt = strcnt, chcnt;
	//第一次基数排序
	for (i = 0; i < m; i++) cnt[i] = 0;
	for (i = 0; i < n; i++) cnt[x[i] = str[i]]++;
	for (i = 1; i < m; i++) cnt[i] += cnt[i - 1];
	for (i = n - 1; i >= 0; i--) sa[--cnt[x[i]]] = i;
	//倍增长度排序
	for (chcnt = 1, j = 1; chcnt < n; j <<= 1, m = chcnt) {
		//根据第二关键字排序,可以由上一次得到的sa值获得
		for (i = n - j, chcnt = 0; i < n; i++) y[chcnt++] = i;
		for (i = 0; i < n; i++) if (sa[i] >= j) y[chcnt++] = sa[i] - j;
		//根据第一关键字排序
		for (i = 0; i < m; i++) cnt[i] = 0;
		for (i = 0; i < n; i++) cnt[x[y[i]]]++;
		for (i = 1; i < m; i++) cnt[i] += cnt[i - 1];
		for (i = n - 1; i >= 0; i--) sa[--cnt[x[y[i]]]] = y[i];
		//根据sa值重新计算名次数组
		swap(x, y);
		for (chcnt = 1, x[sa[0]] = 0, i = 1; i < n; i++) {
			bool eql = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + j] == y[sa[i - 1] + j];
			x[sa[i]] = eql ? chcnt - 1 : chcnt++;
		}
	}
}

char dict[maxn];

void query(int len) {
	int l = 0, r = len, ansstr = 0, clen;
	clen = strlen(dict);
	while (l <= r) {
		int mid = (l + r) >> 1;
		bool ok = !strncmp(dict, buf + sa[mid], clen);
		if (ok) {
			ansstr = mid; r = mid - 1;
		}
		else l = mid + 1;
	}
	for (int i = ansstr; !strncmp(dict, buf + sa[i], clen); i++) {
		printf("find %s at pos %d\n", dict, sa[i]);
	}
}

int main() {
	while (scanf("%s", buf) != EOF) {
		len = 0;
		while (buf[len] != 0) {
			str[len] = idx(buf[len]);
			len++;
		}
		str[len] = 0;
		build_sa(str, sa, len + 1, 27);
		int N; scanf("%d", &N);
		for (int i = 0; i < N; i++) {
			scanf("%s", dict);
			query(len + 1);
		}
	}
	return 0;
}

  

时间: 2024-11-01 12:29:08

后缀数组解决在线的多模板匹配问题的相关文章

后缀数组(Suffix Array)模板及简析——Part 1:构建SA和rank数组

后缀数组(Suffix Array,SA)是处理字符串的有力工具.它比后缀树更易实现,占用空间更少,并且同样可以解决千变万化的字符串问题 首先推荐罗穗骞的论文(网上搜一下就能搜到),里面对后缀数组的定义.实现和应用都做了详细的阐述 然而不幸的是罗神犇的代码简直魔性,蒟蒻表示这代码压的根本看不懂啊…… 所以在理解了后缀数组的构建过程之后,我重新写了一份模板代码.虽然啰嗦了点(代码比较大,而且变量名故意拉长了),不过相对比较好懂 而且论文中用到的辅助空间是4N,我的模板用了3N,事实上还可以优化到只

hiho一下122周 后缀数组三&#183;重复旋律

后缀数组三·重复旋律3 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列.小Hi在练习过很多曲子以后发现很多作品中的旋律有共同的部分. 旋律是一段连续的数列,如果同一段旋律在作品A和作品B中同时出现过,这段旋律就是A和B共同的部分,比如在abab 在 bababab 和 cabacababc 中都出现过.小Hi想知道两部作品的共同旋律最长是多少? 解题方法提示 输入 共两行.一

后缀数组(1)

感觉跟字符串有关的算法都难飞了:) 首先入坑是noi day2t2,舔题解开启后缀数组副本 首先自然是模板题刷水,因为(爱情怎莫会有沧桑)懒,所以没写过基数排序,所以舔模板也舔地十分困难,最后还是跪求zl老爷讲解,,,然而当时也是美得朦胧... 不过还好之前舔了集训队论文->算法合集之<后缀数组——处理字符串的有力工具> 1 #include<stdio.h> 2 #include<string.h> 3 #define maxn 100005 4 char st

URAL1297 Palindrome(后缀数组)

求一个串的最大回文字串. 可以用后缀数组解决. 分别考虑奇数和偶数回文子串的情况,枚举原串S的每个位置i作为中间位置看其能向左右两边同时拓展都哪儿:把原串S反转成S',拼接SaS'(a为一个特殊字符),最远拓展的地方便可以通过LCP(suffix[i],suffix[i'])求得,i'为i对应在S‘的位置. 另外题目要求第一个出现的最长回文串,从左到右枚举中间位置得到的肯定就是出现最早的. 1 #include<cstdio> 2 #include<cstring> 3 #incl

Blue Jeans - poj 3080(后缀数组)

大致题意: 给出n个长度为60的DNA基因(A腺嘌呤 G鸟嘌呤 T胸腺嘧啶 C胞嘧啶)序列,求出他们的最长公共子序列 使用后缀数组解决 1 #include<stdio.h> 2 #include<string.h> 3 char str[6200],res[6200]; 4 int num[6200],loc[6200]; 5 int sa[6200],rank[6200],height[6200]; 6 int wa[6200],wb[6200],wv[6200],wd[620

后缀数组模板及解释

以前做过后缀数组,直接用模板,最近打算重新认真的学一遍.感觉学一个东西一定要弄懂了,不然到最后还是要重学. int wa[MAXN],wb[MAXN],wv[MAXN],Ws[MAXN]; void da(int *r,int *sa,int n,int m){//n表示字符串长度 + 1,包括添加的那个0,m表示取值的范围 //把单个字符进行基数排序 int *x = wa,*y = wb; for(int i = 0; i < m; i++)Ws[i] = 0; for(int i = 0;

后缀数组模板第一版

/*---------------倍增算法+RMQ后缀数组模板-------------- 输入:从0开始的字符串g,长度len最大为10^6 输出: sa[]表示:n 个后缀从小到大进行排序之后把排好序的后缀的开头位置顺 次放入 sa 中,sa[i]表示排第i位的字符串开头是sa[i],因为添加了一个结尾0,所以sa[0]=len height 数组(h[]):定义 h[i]=suffix(sa[i-1])和 suffix(sa[i])的最长公 共前缀,也就是排名相邻的两个后缀的最长公共前缀.

[模板] 后缀数组 C++

以下模板单单注释了如何使用,算法详解可参考 罗穗骞<后缀数组——处理字符串的有力工具> 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 5 using namespace std; 6 7 const int maxn = //长度范围 8 const int maxm = //字符范围

cf244D. Match &amp; Catch 字符串hash (模板)或 后缀数组。。。

D. Match & Catch 可以用各种方法做,字符串hash,后缀数组,dp,拓展kmp,字典树... 字符串hash(模板) http://blog.csdn.net/gdujian0119/article/details/6777239 BKDR Hash Function : // BKDR Hash Function unsigned int BKDRHash(char *str) { unsigned int seed = 131; // 31 131 1313 13131 13