hdu1403 后缀数组入门题

//1403

思路:字符串的任何一个子串都是这个字符串的某个后缀的前缀,则求A和B的最长公共子串等价于求A的后缀和B的后缀的最长公共前缀的最大值。

做法:将第二个字符串写在第一个字符串后面,中间用一个没有出现过的字符隔开,再求这个新的字符串的后缀数组。

 1 #include "bits/stdc++.h"
 2 using namespace std;
 3 const int maxn = 1e6 + 10;
 4 char str[maxn];
 5 int int_str[maxn];
 6 int len;
 7 int str_rank[maxn], s_r[maxn], rank_str[maxn], a[maxn], b[maxn], h_rank[maxn];
 8
 9 int Count[maxn];
10 void radix(int *str, int *s_r, int *str_rank, int len, int m)
11 {
12     int i;
13     memset(Count, 0, sizeof(Count));
14     for(i = 0; i < len; ++i)
15         ++Count[str[s_r[i]]];
16     for(i = 1; i <= m; ++i)
17         Count[i] += Count[i - 1];
18     for(i = len - 1; i >= 0; --i) {
19         str_rank[--Count[str[s_r[i]]]] = s_r[i];
20     }
21 }
22
23 void suffix_array(int *str, int *str_rank, int len, int m)
24 {
25     int i;
26     for(i = 0; i < len; ++i)
27         s_r[i] = i;
28     radix(str, s_r, str_rank, len, m);
29     rank_str[str_rank[0]] = 0;
30     for(i = 1; i < len; ++i) {
31         rank_str[str_rank[i]] = rank_str[str_rank[i - 1]] + (str[str_rank[i - 1]] != str[str_rank[i]]);
32     }
33     int j;
34     for(i = 0; (1 << i) < len; ++i) {
35         for(j = 0; j < len; ++j) {
36             a[j] = rank_str[j] + 1;
37             b[j] = ((1 << i) + j < len)? rank_str[(1 << i) + j] + 1: 0;
38             str_rank[j] = j;
39         }
40         radix(b, str_rank, s_r, len, len);
41         radix(a, s_r, str_rank, len, len);
42         rank_str[str_rank[0]] = 0;
43         for(j = 1; j < len; ++j) {
44             rank_str[str_rank[j]] = rank_str[str_rank[j - 1]] + (a[str_rank[j - 1]] != a[str_rank[j]] || b[str_rank[j - 1]] != b[str_rank[j]]);
45         }
46     }
47 }
48
49 void cal_h(int *str, int *str_rank, int *h_rank, int len)
50 {
51     int i, k = 0;
52     for(i = 0; i < len; ++i) {
53         rank_str[str_rank[i]] = i;
54     }
55     for(i = 0; i < len; ++i) {
56         k = (k == 0? 0: k - 1);
57         if(rank_str[i] != 0) {
58             while(str[i + k] == str[str_rank[rank_str[i] - 1] + k])
59                 ++k;
60         }
61         h_rank[rank_str[i]] = k;
62     }
63 }
64
65
66 int main()
67 {
68     while(scanf("%s", str) != EOF) {
69         len = strlen(str);
70         int len1 = len;
71         str[len] = ‘a‘ - 1;
72         scanf("%s", str + len + 1);
73         len = strlen(str);
74         int i;
75         for(i = 0; i < len; ++i)
76             int_str[i] = str[i];
77         suffix_array(int_str, str_rank, len, 200);
78         cal_h(int_str, str_rank, h_rank, len);
79
80 //        for(i = 0; i < len; ++i) {
81 //            printf("%d: %s %d\n", i + 1, str + str_rank[i], h_rank[i]);
82 //        }
83
84         int res = 0;
85         for(i = 1; i < len; ++i) {
86             if(res < h_rank[i] && ((str_rank[i] < len1 && str_rank[i - 1] > len1) || (str_rank[i] > len1 && str_rank[i - 1] < len1)))
87                 res = h_rank[i];
88         }
89         printf("%d\n", res);
90     }
91
92 }
时间: 2024-08-05 11:18:38

hdu1403 后缀数组入门题的相关文章

poj 2774 Long Long Message(后缀数组入门题)

1 /****************************************************************** 2 题目: Long Long Message(poj 2774) 3 链接: http://poj.org/problem?id=2774 4 题意: 给两个字符串,找最长的公共子串 5 算法: 后缀数组 6 算法思想: 后缀数组就是套模板求先应得数组,这题用到了两个数组,分 7 别是sa[],height[];sa[i]表示所有后缀按字典数排序后以s[i

Long Long Message 后缀数组入门题

Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 22564   Accepted: 9255 Case Time Limit: 1000MS Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days:

后缀数组入门

基础介绍: http://www.nocow.cn/index.php/%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84 应用:整理自<后缀数组--处理字符串的有力工具> 2.1.最长公共前缀 这里先介绍后缀数组的一些性质. height数组:定义height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀.那么对于j和k,不妨设rank[j]<rank[k],则有以下性质: suffix(j

poj 1743 Musical Theme(男人八题&amp;后缀数组第一题)

Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 17298   Accepted: 5939 Description A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range 1..88, each representing a key on the

后缀数组入门(二)——Height数组与LCP

前言 看这篇博客前,先去了解一下后缀数组的基本操作吧:后缀数组入门(一)--后缀排序. 这篇博客的内容,主要建立于后缀排序的基础之上,进一步研究一个\(Height\)数组以及如何求\(LCP\). 什么是\(LCP\) \(LCP\),即\(Longest\ Common\ Prefix\),是最长公共前缀的意思. 而在后缀数组中,\(LCP(i,j)\)表示后缀\(_{SA_i}\)与后缀\(_{SA_j}\)的最长公共前缀的长度,注意是\(SA_i\)和\(SA_j\),而不是\(i\)和

后缀数组 模板题 hdu1403(最长公共(连续)子串)

好气啊,今天没有看懂后缀树和后缀自动机 只能写个后缀数组发泄一下了orz #include <cstdio> #include <cstring> const int N = 100017*2; int wa[N], wb[N], wv[N], ws[N]; int rank[N]; int height[N]; char str[N]; int s[N], sa[N]; int cmp(int *r, int a, int b, int l) { return r[a]==r[b

HDU 1166 敌兵布阵【树状数组入门题】

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 74051    Accepted Submission(s): 31080 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

后缀数组刷题总结

T1:Sandy的卡片 做这道题时对$height[]$理解不深刻,导致一晚上没$A$掉这道题 显然是把差值当成字符数组,把串连起来处理出$height[]$ 之后二分,开一个栈记录存储出现的元素,只要元素个数大于等于$n$即可判断合法 T2:喵星球上的点名 延续上一道题的套路,把名字和询问连成一个串 之后对于每个询问的起始位置二分出左右能做贡献的区间 现在问题转化为m个区间,求每个区间的不同颜色个数以及每个颜色的出现次数 可以用莫队解决 (然而二分完直接暴扫也可以$AC$) T3:字符串 直接

hdu1403(后缀数组模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403 题意: 给出两个字符串, 求他们的最长公共子串 思路: 两个字符串的最长公共子串长度显然就是两个字符串的所有后缀中的最长公共前缀长度. 可以先用一个没有出现的字符(便于后面区分后缀是否属于相同字符串)将两个字符串连成一个字符串,再用后缀数组求其height, SA数组, 对于当前 i, 通过 SA 数组区分后缀 i 和 i - 1 是否在同一个初始字符串中, 若不是则用 height[i] 维