Description
Little cat在Byterland的首都读物理专业。这些天他收到了一条悲伤地信息:他的母亲生病了。担心买火车票花钱太多(Byterland是一个巨大的国家,因此他坐火车回家需要16小时),他决定只给母亲发短信。
Little cat的家境并不富裕,因此他经常去营业厅查看自己发短信花了多少钱。昨天营业厅的电脑坏掉了,打印出两条很长的信息。机智的little cat很快发现:
1.信息中所有的字符都是小写英文字母,没有标点和空格。
2.所有的短信都被连在了一起——第i+1条短信直接接在第i条短信后面——这就是这两条信息如此长的原因。
3.虽然他发的短信都被连在了一起,但由于电脑坏掉了,它们的左边或右边都可能会有许多冗余字符。
例如:如果短信是"motheriloveyou",电脑打印出的每条信息都可能是 "hahamotheriloveyou", "motheriloveyoureally", "motheriloveyouornot", "bbbmotheriloveyouaaa",等等。
4.因为这些乱七八糟的问题,little cat打印了两遍(所以有两条非常长的信息)。尽管原始的短信文本在两条信息中都一样,但两条信息在文本两侧的冗余字符都可能不一样。
给出这两条很长的信息,输出little cat写下的原始短信文本的最长可能长度。
背景:
在Byterland,短信按照美元/字节的单位计价。这就是little cat想要知道原始文本最长可能长度的原因。
为什么让你写一个程序?有四个原因:
1.little cat这些天忙于他的物理课程。
2.little cat不想透露他对母亲说了什么。
3.POJ是个好网站。
4.little cat想要从POJ那里挣点钱,并尝试说服他的母亲去医院
Input
两行两个由小写英文字母组成的字符串。字符串长度都不会超过100000
Output
一行一个整数,即little cat写下的原始文本的最长可能长度。
Sample Input
yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother
Sample Output
27
Hint
Source
POJ 2774 Long Long Message
后缀数组, 字符串, 模式匹配
这道题大意就是求两个字符串的最长公共子串。显然可以用后缀数组来做,但我太弱并不会。于是用字符串哈希来做。
1 #include <map> 2 #include <set> 3 #include <cmath> 4 #include <queue> 5 #include <stack> 6 #include <cstdio> 7 #include <string> 8 #include <vector> 9 #include <cstring> 10 #include <complex> 11 #include <cstdlib> 12 #include <iostream> 13 #include <algorithm> 14 #define ull unsigned long long 15 16 using namespace std; 17 18 inline int gi() 19 { 20 register int r = 0; register bool b = 1; register char c = getchar(); 21 while (c < '0' || c > '9') { if (c == '-') b = 0; c = getchar(); } 22 while (c >= '0' && c <= '9') { r = r * 10 + c - '0', c = getchar(); } 23 if (b) return r; return -r; 24 } 25 26 const int inf = 2147483647, N = 100005, base = 131; 27 int n,m; 28 ull p[N],a[N],h1[N],h2[N]; 29 char s[N],t[N]; 30 31 inline void gethash () 32 { 33 register int i,len; len = max(n,m); 34 p[0] = 1; for (i=1; i<=len; i++) p[i] = p[i-1] * base; // 预处理 base 的 i 次方 35 h1[0] = 0; for (i=1; i<=n; i++) h1[i] = h1[i-1] * base + s[i-1]; // hash 第一个字符串 注意 h1[i] 存的是前缀 i-1 的哈希值 36 h2[0] = 0; for (i=1; i<=m; i++) h2[i] = h2[i-1] * base + t[i-1]; // hash 第二个字符串 同上 37 } 38 39 inline bool check (register int t) 40 { 41 register int i,tot; tot = 0; 42 register ull h; 43 for (i=t; i<=n; i++) a[tot++] = h1[i] - h1[i-t] * p[t]; //取出第一个字符串所有长度为 t 的子串的哈希值 所有长度为 t 的子串由前缀 i 去掉前缀 i-t 得到 44 sort (a,a+tot); //为 binary_search 做准备 binary_search 为二分查找一个数是否在一个数组中出现过 45 for (i=t; i<=m; i++) 46 { 47 h = h2[i] - h2[i-t] * p[t]; 48 if (binary_search (a,a+tot,h)) return 1; //枚举第二个串的所有长度为 t 的子串,看它的哈希值有没有出现过 49 } 50 return 0; 51 } 52 53 int main() 54 { 55 // freopen ("POJ-2774.in", "r", stdin); 56 // freopen ("POJ-2774.out", "w", stdout); 57 register int l,r,mid,ans; 58 scanf ("%s%s",s,t); 59 n = strlen(s), m = strlen(t); 60 gethash (); 61 l = 0, r = min(n,m); //二分答案 注意要用 ans 记录答案,不能输出 l 或 r (可以被 hack 掉) 62 while (l <= r) 63 { 64 mid = (l + r) >> 1; 65 if (check (mid)) l = mid + 1, ans = mid; 66 else r = mid - 1; 67 } 68 printf ("%d ",ans); 69 return 0; 70 }