hdu_1403_Longest Common Substring(后缀数组的应用)

题目链接:hdu_1403_Longest Common Substring

题意:

给你两个字符串,然你找最长的公共子串

题解:

后缀数组的经典应用,要找两个字符串的公共子串,那么就相当于找两个串的后缀的最长公共前缀,我们将两个字符串拼接在一起,中间插一个特殊字符

然后我们考虑height数组,height数组存的是排i和i-1的最长前缀,如果sa[i]和sa[i-1]在特殊字符的两边,那么这个height[i]记录的就是这两个串的最长

子串,然后扫一遍height数组更新一下答案就行了

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;++i)
 3 using namespace std;
 4
 5 namespace suffixarray{
 6     #define FN(n) for(int i=0;i<n;i++)
 7     const int N =2E5+7;//字符串长度
 8     int rnk[N],sa[N],height[N],c[N];char s[N];
 9     void getsa(int n,int m,int *x=rnk,int *y=height){
10         FN(m)c[i]=0;FN(n)c[x[i]=s[i]]++;FN(m)c[i+1]+=c[i];
11         for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
12         for(int k=1,p;p=0,k<=n;k=p>=n?N:k<<1,m=p){
13             for(int i=n-k;i<n;i++)y[p++]=i;
14             FN(n)if(sa[i]>=k)y[p++]=sa[i]-k;
15             FN(m)c[i]=0;FN(n)c[x[y[i]]]++;FN(m)c[i+1]+=c[i];
16             for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
17             swap(x,y),p=1,x[sa[0]]=0;
18             for(int i=1;i<n;i++)
19             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
20         }
21         FN(n)rnk[sa[i]]=i;
22         for(int i=0,j,k=0;i<n-1;height[rnk[i++]]=k)
23         for(k=k?k-1:k,j=sa[rnk[i]-1];s[i+k]==s[j+k];k++);
24     }
25 }
26 using namespace suffixarray;
27 int main(){
28     while(~scanf("%s",s))
29     {
30         int len=strlen(s),sz;
31         s[len]=‘$‘;
32         scanf("%s",s+len+1);
33         sz=strlen(s),getsa(sz+1,128);
34         int ans=0;
35         F(i,1,sz)if(ans<height[i]&&(sa[i]-len)*(sa[i-1]-len)<0)ans=height[i];
36         printf("%d\n",ans);
37     }
38     return 0;
39 }

时间: 2024-10-21 13:13:22

hdu_1403_Longest Common Substring(后缀数组的应用)的相关文章

spoj 1811 LCS - Longest Common Substring (后缀自动机)

spoj 1811 LCS - Longest Common Substring 题意: 给出两个串S, T, 求最长公共子串. 限制: |S|, |T| <= 1e5 思路: dp O(n^2) 铁定超时 后缀数组 O(nlog(n)) 在spoj上没试过,感觉也会被卡掉 后缀自动机 O(n) 我们考虑用SAM读入字符串B; 令当前状态为s,同时最大匹配长度为len; 我们读入字符x.如果s有标号为x的边,那么s=trans(s,x),len = len+1; 否则我们找到s的第一个祖先a,它

poj Common Substrings(后缀数组&amp;单调队列)

Common Substrings Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7082   Accepted: 2355 Description A substring of a string T is defined as: T(i, k)=TiTi+1...Ti+k-1, 1≤i≤i+k-1≤|T|. Given two strings A, B and one integer K, we define S, a

poj 3693 Maximum repetition substring(后缀数组)

题目链接:poj 3693 Maximum repetition substring 题目大意:求一个字符串中循环子串次数最多的子串. 解题思路:对字符串构建后缀数组,然后枚举循环长度,分区间确定.对于一个长度l,每次求出i和i+l的LCP,那么以i为起点,循环子串长度为l的子串的循环次数为LCP/l+1,然后再考虑一下从i-l+1~i之间有没有存在增长的可能性. #include <cstdio> #include <cstring> #include <vector>

POJ - 3693 Maximum repetition substring(后缀数组求重复次数最多的连续重复子串)

Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1. Given a

hdu 5769 Substring 后缀数组 + KMP

http://acm.hdu.edu.cn/showproblem.php?pid=5769 题意:在S串中找出X串出现的不同子串的数目? 其中1 官方题解: 处理出后缀数组中的sa[]数组和height[]数组.在不考虑包含字符X的情况下,不同子串的个数为 如果要求字符X,只需要记录距离sa[i]最近的字符X的位置(用nxt[sa[i]]表示)即可,个数 理解:后缀数组height[i]就是sa[i]与sa[i-1]的LCP,在后缀数组中求解全部的不同子串(之前只写过SAM处理所有不同子串..

2016多校联合训练4 F - Substring 后缀数组

Description ?? is practicing his program skill, and now he is given a string, he has to calculate the total number of its distinct substrings. But ?? thinks that is too easy, he wants to make this problem more interesting. ?? likes a character X very

POJ 3693 Maximum repetition substring ——后缀数组

重复次数最多的字串,我们可以枚举循环节的长度. 然后正反两次LCP,然后发现如果长度%L有剩余的情况时,答案是在一个区间内的. 所以需要找到区间内最小的rk值. 两个后缀数组,四个ST表,$\Theta(n\log n)$ 就可以解决了 空间卡死了,瞎晶胞卡过去了. #include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #incl

POJ 3415 Common Substrings 后缀数组+并查集

后缀数组,看到网上很多题解都是单调栈,这里提供一个不是单调栈的做法, 首先将两个串 连接起来求height   求完之后按height值从大往小合并.  height值代表的是  sa[i]和sa[i-1] 的公共前缀长度,那么每次合并就是合并  i和i-1 那么在合并小的时候公共前缀更大的肯定已经都合并在一起,那么就可以直接统计了. #include<iostream> #include<cstdio> #include<algorithm> #include<

Substring (后缀数组 + 计数)

题意:求出字符串中包含了某个字符的字符序列不一样的数量. 思路:其实主要的是找出每个被包含字符的数量,假设除了目标字符之外的所有字符都不一样,那么应该就很好求了,但是显然不可能,所以我们可以枚举每一个起点,个数应该是从他的下一个字符是目标字符起的所有数量,但是通过观察我们可以发现这样计算我们又会多计算了一部分,例如a , abbabbabb 在计算第四个和第七个时,我们会多计算了a, ab, abb 或者计算第二位和第五位时多计算了bba,bbab,bbabb,我们可以这是就是相当于后缀数组里面