POJ 2774 后缀数组 || 二分+哈希

Long Long Message

Time Limit: 4000MS   Memory Limit: 131072K
Total Submissions: 35607   Accepted: 14275
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: his mother is getting ill. Being worried about spending so much on railway tickets (Byterland is such a big country, and he has to spend 16 shours on train to his hometown), he decided only to send SMS with his mother.

The little cat lives in an unrich family, so he frequently comes to the mobile service center, to check how much money he has spent on SMS. Yesterday, the computer of service center was broken, and printed two very long messages. The brilliant little cat soon found out:

1. All characters in messages are lowercase Latin letters, without punctuations and spaces.

2. All SMS has been appended to each other – (i+1)-th SMS comes directly after the i-th one – that is why those two messages are quite long.

3. His own SMS has been appended together, but possibly a great many redundancy characters appear leftwards and rightwards due to the broken computer.

E.g: if his SMS is “motheriloveyou”, either long message printed by that machine, would possibly be one of “hahamotheriloveyou”, “motheriloveyoureally”, “motheriloveyouornot”, “bbbmotheriloveyouaaa”, etc.

4. For these broken issues, the little cat has printed his original text twice (so there appears two very long messages). Even though the original text remains the same in two printed messages, the redundancy characters on both sides would be possibly different.

You are given those two very long messages, and you have to output the length of the longest possible original text written by the little cat.

Background:

The SMS in Byterland mobile service are charging in dollars-per-byte. That is why the little cat is worrying about how long could the longest original text be.

Why ask you to write a program? There are four resions:

1. The little cat is so busy these days with physics lessons;

2. The little cat wants to keep what he said to his mother seceret;

3. POJ is such a great Online Judge;

4. The little cat wants to earn some money from POJ, and try to persuade his mother to see the doctor :(

Input

Two strings with lowercase letters on two of the input lines individually. Number of characters in each one will never exceed 100000.

Output

A single line with a single integer number – what is the maximum length of the original text written by the little cat.

Sample Input

yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother

Sample Output

27

这个题目百来就是一道后缀数组的入门题,然后发现二分哈希也能做,于是就都打打。。。

后缀数组:432ms
 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5
 6 using namespace std;
 7
 8 const int N = 202020;
 9
10 int l1, m, n, l2;
11 int c[N], x[N], y[N], sa[N], ht[N], rk[N];
12 char s1[N], s2[N], s[N];
13
14 inline void Get_Sa()
15 {
16     for (int i = 1; i <= n; ++i) ++c[x[i] = s[i]];
17     for (int i = 2; i <= m; ++i) c[i] += c[i - 1];
18     for (int i = n; i >= 1; --i) sa[c[x[i]]--] = i;
19     for (int k = 1; k <= n; k <<= 1)
20     {
21         int num = 0;
22         for (int i = n - k + 1; i <= n; ++i) y[++num] = i;
23         for (int i = 1; i <= n; ++i) if (sa[i] > k) y[++num] = sa[i] - k;
24         for (int i = 1; i <= m; ++i) c[i] = 0;
25         for (int i = 1; i <= n; ++i) ++c[x[i]];
26         for (int i = 2; i <= m; ++i) c[i] += c[i - 1];
27         for (int i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i], y[i] = 0;
28         for (int i = 1; i <= n; ++i) y[i] = x[i], x[i] = 0;
29         swap(x, y), x[sa[1]] = 1, num = 1;
30         for (int i = 2; i <= n; ++i)
31             x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
32         if (num == n) break; m = num;
33     }
34     for (int i = 1; i <= n; ++i) rk[sa[i]] = i;
35 }
36
37 inline void Get_Ht()
38 {
39     int k = 0;
40     for (int i = 1; i <= n; ++i)
41     {
42         if (rk[i] == 1) continue;
43         if (k) --k;
44         int j = sa[rk[i] - 1];
45         while (j + k <= n && i + k <= n
46             && s[i + k] == s[j + k]) ++k;
47         ht[rk[i]] = k;
48     }
49 }
50
51 int main()
52 {
53     while (~scanf("%s%s", s + 1, s2 + 1))
54     {
55         int ans = -21469999;
56         l1 = strlen(s + 1);
57         l2 = strlen(s2 + 1);
58         s[l1 + 1] = ‘$‘;
59         m = 150;
60         for (int i = 1; i <= l2; ++i)
61             s[l1 + 1 + i] = s2[i];
62         n = strlen(s + 1);
63         Get_Sa(), Get_Ht();
64         for (int i = 1; i <= n; ++i)
65             if (sa[i - 1] >= 1 && sa[i - 1] <= l1 && sa[i] >= l1 + 1)
66                 ans = max(ans, ht[i]);
67             else if (sa[i] >= 1 && sa[i] <= l1 && sa[i - 1] >= l1 + 1)
68                 ans = max(ans, ht[i]);
69         // for (int i = 1; i <= n; ++i)
70         //     printf("%s %d\n", s + sa[i], ht[i]);
71         printf("%d\n", ans);
72     }
73     return 0;
74 }

二分+哈希:1463ms

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cstdio>
 6
 7 using namespace std;
 8 typedef unsigned long long ull;
 9
10 const ull N = 202020;
11 const ull base = 131;
12
13 int l1, l2, L, R;
14 ull bit[N], f[N], h1[N], h2[N];
15 char s2[N], s1[N];
16
17 inline bool good(int l)
18 {
19     int tot = 0;
20     for (int i = 1; i <= l1 - l + 1; ++i)
21         f[++tot] = h1[i + l - 1] - h1[i - 1] * bit[l];
22     sort(f + 1, f + tot + 1);
23     for (int i = 1; i <= l2 - l + 1; ++i)
24         if (binary_search(f + 1, f + tot + 1, h2[i + l - 1] - h2[i - 1] * bit[l]))
25             return true;
26     return false;
27 }
28
29 int main()
30 {
31     for (int i = 1; i <= N - 5; ++i) bit[i] = (i == 1 ? 1 : bit[i - 1]) * base;
32     while (~scanf("%s%s", s1 + 1, s2 + 1))
33     {
34         l1 = strlen(s1 + 1), l2 = strlen(s2 + 1);
35         for (int i = 1; i <= l1; ++i) h1[i] = h1[i - 1] * base + (s1[i] - 90);
36         for (int i = 1; i <= l2; ++i) h2[i] = h2[i - 1] * base + (s2[i] - 90);
37         L = 0, R = max(l1, l2) + 1;
38         while (L <= R)
39         {
40             int mid = (L + R) >> 1;
41             if (good(mid)) L = mid + 1;
42             else R = mid - 1;
43         }
44         printf("%d\n", R);
45     }
46     return 0;
47 }

(虽然慢一点,但哈希真的好写!!!!)

原文地址:https://www.cnblogs.com/yanyiming10243247/p/10094740.html

时间: 2024-12-10 20:03:40

POJ 2774 后缀数组 || 二分+哈希的相关文章

POJ 2774 后缀数组:求最长公共子串

思路:其实很简单,就是两个字符串连接起来,中间用个特殊字符隔开,然后用后缀数组求最长公共前缀,然后不同在两个串中,并且最长的就是最长公共子串了. 注意的是:用第一个字符串来判断是不是在同一个字符中,刚开始用了第二个字符的长度来判断WA了2发才发现. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<

POJ 2774 后缀数组

题目链接:http://poj.org/problem?id=2774 题意:给定两个只含小写字母的字符串,求字符串的最长公共子串长度. 思路:根据<<后缀数组——处理字符串的有力工具>>的思路,字符串的任何一个子串都是这个字符串的某个后缀的前缀 .求 A和 B的最长公共子串等价于求 A的后缀和 B的后缀的最长公共前缀的最大值. 如果枚举 A 和 B的所有的后缀,那么这样做显然效率低下.由于要计算 A的后缀和 B的后缀的最长公共前缀, 所以先将第二个字符串写在第一个字符串后面, 中

POJ 3261 (后缀数组 二分) Milk Patterns

这道题和UVa 12206一样,求至少重复出现k次的最长字串. 首先还是二分最长字串的长度len,然后以len为边界对height数组分段,如果有一段包含超过k个后缀则符合要求. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 20000 + 10; 7 const int maxm = 1000000

POJ 2774 (后缀数组 最长公共字串) Long Long Message

用一个特殊字符将两个字符串连接起来,然后找最大的height,而且要求这两个相邻的后缀的第一个字符不能在同一个字符串中. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 200000 + 10; 7 8 char s[maxn]; 9 int n; 10 int sa[maxn], rank[maxn],

poj 3261 Milk Patterns 后缀数组+二分

1 /*********************************************************** 2 题目: Milk Patterns(poj 3261) 3 链接: http://poj.org/problem?id=3261 4 题意: 给一串数字,求这些数字中公共子串个数大于k的 5 最长串. 6 算法: 后缀数组+二分 7 ***********************************************************/ 8 #incl

poj 3261 后缀数组 找重复出现k次的子串(子串可以重叠)

题目:http://poj.org/problem?id=3261 仍然是后缀数组的典型应用----后缀数组+lcp+二分 做的蛮顺的,1A 但是大部分时间是在调试代码,因为模板的全局变量用混了,而自己又忘了,,,等西安邀请赛还有四省赛结束之后,该冷静反思下尝试拜托模板了 错误   :1.k用错,题目的k和模板的k用混; 2.还是二分的C()函数,这个其实跟前一篇<poj 1226 hdu 1238 Substrings 求若干字符串正串及反串的最长公共子串 2002亚洲赛天津预选题>的C函数

[poj 2274]后缀数组+最长公共子序列

题目链接:http://poj.org/problem?id=2774 后缀数组真的太强大了,原本dp是n^2的复杂度,在这里只需要O(n+m). 做法:将两个串中间夹一个未出现过的字符接起来,然后做一次后缀数组,得到的height相邻两个排名的后缀,在串中的位置如果满足在分界符左右两侧,就更新最长公共前缀.最后得到的最大值就是最长公共子序列. #include<algorithm> #include<cstdio> #include<cstring> using na

POJ 1226后缀数组:求出现或反转后出现在每个字符串中的最长子串

思路:这题是论文里的最后一道练习题了,不过最后一题竟然挺水的. 因为求的是未反转或者反转后,最长公共子串. 刚开始还真不知道怎么构建连接成一个字符串,因为需要有反转嘛! 但是其实挺简单的,把未反转的和反转后的字符串都连起来,中间用未出现过的字符隔开就行了!然后未反转的和反转的在同一组. 二分枚举最长的公共前缀长度,然后统计看看这个最长的长度在不在所有的组里,如果在就符合-- #include<iostream> #include<cstdio> #include<cstrin

POJ 3294 后缀数组:求不小于k个字符串中的最长子串

思路:先把所有的串连接成一个串,串写串之前用没出现过的字符隔开,然后求后缀:对height数组分组二分求得最长的公共前缀,公共前缀所在的串一定要是不同的,不然就不是所有串的公共前缀了,然后记下下标和长度即可. 刚开始理解错题意,然后不知道怎么写,然后看别人题解也不知道怎么意思,后面看了好久才知道题目意思理解错了. 时间四千多ms,别人才一百多ms,不知道别人怎么做的-- #include<iostream> #include<cstdio> #include<cstring&