poj - 2774 - Long Long Message / hdu - 1403 - Longest Common Substring(后缀数组)
2013-08-27 01:23
519 查看
题意:输入2个长度不超过100000的字符串,问它们最长公共子串的长度。
题目链接:http://poj.org/problem?id=2774
——>>后缀数组!后缀数组!
~从LJ的《训练指南》,到许智磊的论文+PPT,吉大的模版,学长的博客,这路还真不容易走。。。
最后决定用LJ《训练指南》的写法,感觉挺精辟的。
合并两个串,中间放一个特殊字符,根据条件(len为第一个串的长度,n为合并后串的长度):
(sa[i] >= 0 && sa[i] < len && sa[i-1] > len && sa[i-1] < n) || (sa[i-1] >= 0 && sa[i-1] < len && sa[i] > len && sa[i] < n)判断是否取height[i],取出最大值。
题目链接:http://poj.org/problem?id=2774
——>>后缀数组!后缀数组!
~从LJ的《训练指南》,到许智磊的论文+PPT,吉大的模版,学长的博客,这路还真不容易走。。。
最后决定用LJ《训练指南》的写法,感觉挺精辟的。
合并两个串,中间放一个特殊字符,根据条件(len为第一个串的长度,n为合并后串的长度):
(sa[i] >= 0 && sa[i] < len && sa[i-1] > len && sa[i-1] < n) || (sa[i-1] >= 0 && sa[i-1] < len && sa[i] > len && sa[i] < n)判断是否取height[i],取出最大值。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 100000 * 2 + 10; char s[maxn], s2[maxn]; int sa[maxn], t1[maxn], t2[maxn], c[maxn], rak[maxn], height[maxn], n; void build_sa(int m){ int i, *x = t1, *y = t2; //基数排序 for(i = 0; i < m; i++) c[i] = 0; for(i = 0; i < n; i++) c[x[i] = s[i]]++; for(i = 1; i < m; i++) c[i] += c[i-1]; //预留空位给比c[i]小的字符 for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i; //从右往左,相等的从大号到小号 for(int k = 1; k < n; k <<= 1){ //每次判断时已算完了长度为k的后缀 int p = 0; //直接用sa数组排序第二关键字 for(i = n-k; i < n; i++) y[p++] = i; for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k; //刚才是sa[i]位,倍增后左移变位于sa[i]-k位 //第二关键字排完序后已连成一条链,从端开始扫描就是 //基数排序第一关键字 for(i = 0; i < m; i++) c[i] = 0; for(i = 0; i < n; i++) c[x[y[i]]]++; for(i = 1; i < m; i++) c[i] += c[i-1]; for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; //从右往左扫描y[i]是第二关键字从大到小,它应放到第一关键字相同的最右 //根据sa和y数组计算新的x数组 swap(x, y); //此时y数组变得没意义,但更新x数组又要用到原来的x数组,所以将原来的x数组存到y数组里 p = 1; x[sa[0]] = 0; //(以下类似于离散化)最小的那1位赋0,接着开始从小到大扫描 for(i = 1; i < n; i++) x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+k] == y[sa[i]+k] ? p-1 : p++; if(p >= n) break; m = p; } } void getHeight(){ int i, j, k = 0; for(i = 0; i < n; i++) rak[sa[i]] = i; height[0] = 0; for(i = 0; i < n; i++){ if(!rak[i]) continue; //注意判空! if(k) k--; //height[rank[i]] >= height[rank[i-1]] - 1 j = sa[rak[i]-1]; //等级比i小1的后缀编号为j while(s[i+k] == s[j+k]) k++; height[rak[i]] = k; } } void solve(){ int len = strlen(s); s[len] = '$'; s[len+1] = '\0'; strcat(s, s2); n = strlen(s); build_sa(256); getHeight(); int Max = -1, i; for(i = 1; i < n; i++) if((sa[i] >= 0 && sa[i] < len && sa[i-1] > len && sa[i-1] < n) || (sa[i-1] >= 0 && sa[i-1] < len && sa[i] > len && sa[i] < n)) Max = max(Max, height[i]); printf("%d\n", Max); } int main() { while(scanf("%s%s", s, s2) == 2) solve(); return 0; }
相关文章推荐
- POJ 2774 Long Long Message+Hdu 1403 Longest Common Substring (后缀数组 最长公共子串)
- POJ 2774 Long Long Message&&HDU 1403 Longest Common Substring&&COJ 1203
- POJ 2774 Long Long Message&&HDU 1403 Longest Common Substring&&COJ 1203
- poj2774 Long Long Message && hdu 1403 Longest Common Substring 最长公共字串【后缀数组(倍增)】
- HDU 1403 & POJ 2774 Longest Common Substring (后缀数组啊 求最长公共子串 模板题)
- hdu 1403 Longest Common Substring(最长公共子字符串)(后缀数组)
- HDU 1403 Longest Common Substring(后缀自动机——附讲解 or 后缀数组)
- hdu 1403 Longest Common Substring (后缀数组)
- HDU 1403-Longest Common Substring (后缀数组)
- hdu 1403 Longest Common Substring (后缀数组模板)
- HDU 1403 Longest Common Substring(后缀数组入门)
- POJ2774 Long Long Message(后缀数组)
- HDU1403 - Longest Common Substring(后缀数组求nlog(n)的最长公共子序列)
- POJ2774 Long Long Message(后缀数组)
- hdu 1403 Longest Common Substring 后缀数组da算法
- poj 2774 Long Long Message(后缀数组)
- poj 2774 long long message(后缀数组)
- poj 2774 Long Long Message (后缀数组)
- POJ 2774 Long Long Message (后缀数组模板)
- POJ 2774 Long Long Message 后缀数组