两份必备资料:
论文给出的强大模板:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std ;
const int maxn=100000 + 50 ;
// "后缀i" : 以i开头的后缀。
char s[maxn];
int wa[maxn],wb[maxn],wv[maxn],ws[maxn]; // 辅助数组
int r[maxn]; // 原字符串
int sa[maxn]; // 后缀数组 ,即按字典序排在第i位的是哪个后缀? (排序均为从小到大)
int rank[maxn];// 名次数组, 即以i开头的后缀排第几? (从小到大)
int height[maxn]; // 排第i位的后缀和排第i-1位的后缀(即sa[i]和sa[i-1])的最长公共前缀长度。
int cmp(int *r,int a,int b,int l)
{ /* 由于在原串末尾加了个0 ,避免了数组越界,换句话说:若a+l > max_len 或
b+l > max_len, 则必有r[a]!=r[b] ; 如果现在看不懂没关系,读完整个程序再理解!
*/
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int *r,int *sa,int n,int m) // 难点和重点! 计算后缀数组。
{ // n : 字符串长度 , m: 字符ASCII码(即为关键字)的最大值 + 1.
int i,j,p,*x=wa,*y=wb,*t;
for(i=0; i<m; i++) ws[i]=0;
for(i=0; i<n; i++) ws[x[i]=r[i]]++; // x[] 保存的是关键字, 由于只用来比较大小, 不必要连续。
for(i=1; i<m; i++) ws[i]+=ws[i-1];
for(i=n-1; i>=0; i--) sa[--ws[x[i]]]=i; // sa[] 就是只对长度为1的关键字排序得到的后缀数组!!
// 为什么要从n-1到0枚举? 看后面的说明。
/* 上面4行被称为基数排序,不懂没关系,手算模拟下就能理解, 如:
① x[] = r[] = {1,2,3,2,1,0} // 末尾一定加了个0
② ws[0]=1 , ws[1]=2, ws[2]=2, ws[3]= 1 ; // 每个关键字的数量
③ ws[0]=1 , ws[1]=3, ws[2]=5, ws[3]= 6 ; // 关键字个数前缀和,表明每个关键字应该拍的位置。】
④ sa[0]=5 , sa[1]=0, sa[2]=4, sa[3]=1, sa[4]=3, sa[5]=4 ; // 看!已经排好序了!
*/
// 下面就是倍增过程。j: 当前长度。 p:不同关键字的个数。
for(j=1,p=1; p<n; j*=2,m=p)
{
/*
下面2行按第二关键字基数排序排序,得到的后缀数组存在y[]中。
根据上次的sa[] , 可直接计算。
*/
for(p=0,i=n-j; i<n; i++) y[p++]=i; // 最后面的j个"第二关键为0的后缀"排名肯定是最小的!
for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;// 减去j得到整体的开头位置.
/*
下面5行按第一关键字进行基数排序排序,得到的后缀数组存在sa[]中。
*/
for(i=0; i<n; i++) wv[i]=x[y[i]]; // 取出第一关键字
for(i=0; i<m; i++) ws[i]=0;
for(i=0; i<n; i++) ws[wv[i]]++;
for(i=1; i<m; i++) ws[i]+=ws[i-1];
for(i=n-1; i>=0; i--) sa[--ws[wv[i]]]=y[i];
/*
现在来说明为什么要从n-1枚举到0, 这样做的好处是:
第一关键字相同的两个元素还会保持原来的顺序,即按第二关键字排序的结果。
这就是所谓的稳定排序!
*/
/*
下面2行从新计算每个后缀的名次, 保存在x[]中
*/
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
/*
下面的函数用来线性计算rank[]和height[].
原理是: height[rank[i]] >= height[rank[i-1]] - 1 .
其证明请参看相关资料。
*/
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1; i<=n; i++) rank[sa[i]]=i;
for(i=0; i<n; height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++);
return;
}
// 调用方法:
int main()
{
scanf("%s",s) ;
int n= strlen(s) , m =0;
for(int i=0; i<n; i++) r[i] = s[i] , m = max(m , r[i]) ;
r[n++] = 0; // 注意末尾添加0
da(r ,sa ,n , m+1);
calheight(r,sa,n);
/*
然后利用sa[] ,rank[] 和height[] 解决问题。
*/
return 0;
}
常用处理技巧:
① 分组(最常用):把排序后的后缀分成若干组,其中每组的后缀之间的 height 值都不小于 k。
②不可重叠: 只须判断每组的每个后缀的 sa 值的最大值和最小值之差是否不小于k。
③重复至少K次:判断的是有没有一个组的后缀个数不小于 k。
④不同子串个数:suffix(sa[k])将“贡献”出 n-sa[k]+1- height[k]个不同的子串,累加求和。
⑤最长回文子串:将整个字符串反过来写在原字符串后面。
⑥重复次数最多的连续重复子串:先穷举长度 L,S 肯定包括了字符 r[0], r[L], r[L*2],r[L*3], ……中的某相邻的两个。只须看字符 r[L*i]和 r[L*(i+1)]往前和往后各能匹配到多远,记这个总长度为 K,那么这里连续出现了 K/L+1 次。
⑦最长公共子串:求排名相邻但原来不在同一个字符串中的两个后缀的 height 值的最大值。
⑧长度不小于 k 的公共子串的个数: 扫描一遍,每遇到一个 B 的后缀就统计与前面的 A 的后缀能产生多少个长度不小于 k 的公共子串,这里 A 的后缀需要用一个单调的栈来高效的维护。 这个技巧较高。
⑨可“整体偏移,变调”: 处理区差分串。
练习:
1. POJ 1226 Substrings (论文2.4 多个字符串,出现或反转后出现在每个字符串中的最长子串)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
typedef long long LL;
const int maxn=21111 ;
char ss[maxn];
int r[maxn],sa[maxn],rank[maxn],height[maxn],id[maxn] ;
int wa[maxn],wb[maxn],ky[maxn],cn[maxn] ;
inline bool cmp(int*r,int a,int b,int l){
return r[a]==r[b] && r[a+l]==r[b+l] ;
}
void build_sa(int *r,int *sa,int n , int m){
int i,k,p,*x=wa,*y=wb;
for(i=0; i<m; i++) cn[i] = 0;
for(i=0; i<n; i++) cn[ x[i]=r[i] ]++ ;
for(i=1; i<m; i++) cn[i] += cn[i-1] ;
for(i=n-1; i>=0 ;i--) sa[ --cn[x[i]] ] = i;
for(k=1,p=1; p<n ; k<<=1 ,m=p){
for(i=n-k, p=0; i<n ;i++) y[p++] = i ;
for(i=0; i<n; i++) if(sa[i]>=k) y[p++]= sa[i]-k ;
for(i=0; i<n; i++) ky[i] = x[y[i]] ;
for(i=0; i<m; i++) cn[i] = 0;
for(i=0; i<n; i++) cn[ky[i]]++ ;
for(i=1; i<m; i++) cn[i] += cn[i-1] ;
for(i=n-1; i>=0 ;i--) sa[--cn[ky[i]]] = y[i] ;
for(swap(x,y),x[sa[0]]=0,p=1,i=1;i<n;i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],k) ? p-1 : p++ ;
}
return ;
}
void get_height(int *r ,int n){
for(int i=0;i<n;i++) rank[sa[i]] = i ;
int k=0;
for(int i=0;i<n;i++){
if(k) k-- ;
int j=sa[rank[i]-1] ;
while(r[i+k] == r[j+k]) k++ ;
height[rank[i]] = k;
}
}
bool check(int n, int N, int limit){
set<int>vis;
vis.insert(id[sa[1]]) ;
for(int i=2;i<n;i++) {
while(i<n && height[i] >= limit) vis.insert(id[sa[i++]]) ;
if((int)vis.size() >=N) return true ;
vis.clear() ;
vis.insert(id[sa[i]]) ;
}
return false ;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
int N, n=0, mx = 'z'+1 ;
scanf("%d" ,&N);
for(int i=1,j=0; i<=N; i++) {
scanf("%s",ss);
for(j=0;ss[j];j++) id[n]=i , r[n++]=ss[j];
id[n]=i, r[n++] = mx++ ;
for(j--;j>=0;j--) id[n]=i , r[n++] = ss[j] ;
id[n]=i , r[n++] = mx++ ;
}
id[n] = -1 , r[n++] = 0 ;
if(N==1){
printf("%d\n" , strlen(ss)) ;
continue ;
}
build_sa(r,sa,n,mx);
get_height(r,n);
int L=0 , R = 100 , mid ;
while(L<R){
mid = L + (R-L+1)/2;
if(check(n,N,mid)) L = mid ;
else R = mid-1 ;
}
printf("%d\n" , L);
}
return 0;
}
2. UVA - 11107 Life Forms (论文2.4 多个字符串,不小于 k 个字符串中的最长子串)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
const int maxn = 110 * 1011 ;
char read[maxn] ;
int r[maxn] ;
int sa[maxn], height[maxn] ,rank[maxn] , id[maxn] ;
int wa[maxn] ,wb[maxn], ky[maxn], cn[maxn] ;
inline bool cmp(int *r ,int a,int b,int l){
return r[a]==r[b] && r[a+l] == r[b+l] ;
}
void build_sa(int *r, int *sa ,int n , int m){
int i, k , p , *x=wa ,*y = wb;
for(i=0; i<m; i++) cn[i] = 0;
for(i=0; i<n; i++) cn[ x[i] = r[i] ] ++ ;
for(i=1; i<m; i++) cn[i] += cn[i-1] ;
for(i=n-1; i>=0; i--) sa[ --cn[ x[i] ] ] = i ;
for(k=1,p=1; p<n; k<<=1 , m=p) {
for(p=0,i=n-k; i<n; i++) y[p++] = i ;
for(i=0; i<n; i++) if(sa[i] >=k ) y[p++] = sa[i] - k ;
for(i=0; i<n; i++) ky[i] = x[ y[i] ] ;
for(i=0; i<m; i++) cn[i] = 0;
for(i=0; i<n; i++) cn[ky[i]]++ ;
for(i=1; i<m; i++) cn[i] += cn[i-1] ;
for(i=n-1; i>=0; i--) sa[ --cn[ky[i]] ] = y[i] ;
for(swap(x ,y),p=1,x[sa[0]]=0,i=1; i<n; i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],k) ? p-1 : p++ ;
}
return ;
}
void get_height(int *s, int n) {
int i, j , k=0;
for(i=0; i<n; i++) rank[sa[i]] = i ;
for(i=0; i<n-1; i++) {
if(k) k-- ;
j = sa[rank[i]-1] ;
while(s[i+k] == s[j+k]) k++ ;
height[rank[i]] = k;
}
}
bool check(int n ,int m, int mid) {
set<int>vis ;
vis.insert( id[ sa[1] ] ) ;
for(int i=2; i<n; i++) {
while(i<n && height[i] >= mid) vis.insert(id[ sa[i] ]) , i++ ;
if(vis.size()*2 > m) return true ;
vis.clear();
vis.insert(id[ sa[i] ]) ;
}
return false ;
}
void print(int n, int m, int p) {
set<int>vis ;
vis.insert(id[ sa[1] ]) ;
for(int i=2; i<n; i++) {
while(i<n && height[i] >= p) vis.insert(id[sa[i]]) , i++ ;
if(vis.size() * 2 > m) {
int a = sa[i-1] ;
for(int j=0; j<p ;j++) putchar(r[a+j]) ;
puts("") ;
}
vis.clear() ;
vis.insert(id[sa[i]]) ;
}
}
int main()
{
int m , first = 1 ;
while(scanf("%d" ,&m)==1 && m) {
if(!first) puts("") ; first = 0;
int n = 0;
for(int i=1; i<=m; i++) {
scanf("%s" , read) ;
for(int j=0; read[j] ; j++) {
id[n]=i;
r[n++] = read[j] ;
}
id[n] = i;
r[n++] = 'z' + i ;
}
if( m==1 ){
puts(read) ;
continue ;
}
id[n] = m+1 , r[n++] = 0 ;
build_sa(r , sa , n, 'z'+m+2) ;
get_height(r , n) ;
// debug :
// for(int i=1; i<n ; i++)
// printf("%d %d : %s\n", i, height[i] , r+sa[i]);
if(!check(n , m , 1)) {
puts("?") ;
continue ;
}
int L = 1 , R = 1000;
while(L<R) {
int mid = L + (R-L+1)/2 ;
if(check(n , m, mid)) L = mid ;
else R = mid -1 ;
}
print(n ,m ,L) ;
}
return 0;
}
3. POJ 1743 Musical Theme (论文2.2.1, 单个字符串, 不可重叠最长重复子串)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
const int INF = 1e8;
const int maxn = 20100;
int r[maxn] , s[maxn] , head[maxn] ;
int wa[maxn] , wb[maxn] , ky[maxn] , cn[maxn] ;
int sa[maxn] , height[maxn] , rank[maxn] ;
inline bool cmp(int *r,int a,int b,int l) {
return r[a]==r[b] && r[a+l]==r[b+l];
}
void build_sa(int *r ,int *sa ,int n ,int m) {
int i ,k ,p ,*x=wa ,*y=wb ;
for(i=0; i<m; i++) cn[i] = 0;
for(i=0; i<n; i++) cn[x[i]=r[i]] ++ ;
for(i=1; i<m; i++) cn[i] += cn[i-1] ;
for(i=n-1;i>=0;i--) sa[ --cn[x[i]] ] = i ;
for(k=1,p=1;p<n;k<<=1,m=p) {
for(i=n-k,p=0 ; i<n; i++) y[p++] = i;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++] = sa[i] - k ;
for(i=0;i<n;i++) ky[i] = x[y[i]] ;
for(i=0;i<m;i++) cn[i] = 0;
for(i=0;i<n;i++) cn[ky[i]]++ ;
for(i=1;i<m;i++) cn[i]+=cn[i-1];
for(i=n-1;i>=0;i--) sa[--cn[ky[i]]] = y[i] ;
for(swap(x,y),x[sa[0]]=0,p=1,i=1; i<n; i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],k) ? p-1 : p++ ;
}
}
void cal_height(int *r,int n){
for(int i=0; i<n; i++) rank[sa[i]] = i ;
int k=0;
for(int i=0;i<n;i++){
if(k) k-- ;
int j=sa[rank[i]-1] ;
while(r[i+k] == r[j+k]) k++ ;
height[rank[i]] = k ;
}
}
bool check(int limit ,int n) {
int p = 1 ;
for(int i=2; i<n; i++) {
for(;i<n && height[i]>=limit; i++) ;
int L = INF , R = -INF ;
for(int j=p; j<i ;j++) {
L = min(L , sa[j]) ;
R = max(R , sa[j]) ;
if(R - L >= limit+1) return true ;
}
p=i ;
}
return false ;
}
int main()
{
int N ;
while(scanf("%d" ,&N)==1 && N) {
int n = 0 ;
for(int i=0; i<N ;i++) scanf("%d", &s[i]) ;
if(N<10) { printf("0\n") ; continue ;}
for(int i=1; i<N ;i++) {
r[n++] = s[i] - s[i-1] + 90 ;
}
r[n++] = 0 ;
build_sa(r,sa,n,200) ;
cal_height(r ,n) ;
int L = 0 , R = N/2;
while(L < R) {
int mid = L + (R-L+1)/2 ;
if(check(mid , n)) L = mid ;
else R = mid - 1 ;
}
L++ ;
if(L<5) L = 0 ;
printf("%d\n" , L) ;
}
return 0;
}
4. POJ 2774 Long Long Message (论文2.3.1 两个字符串,最长公共子串)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 200050 ;
char buf[maxn] ;
int r[maxn], wa[maxn] , wb[maxn] , ky[maxn] , cn[maxn] ;
int sa[maxn] ,height[maxn] ,rank[maxn], id[maxn] ;
inline bool cmp(int *r,int a,int b,int l){
return r[a] == r[b] && r[a+l] == r[b+l];
}
void build_sa(int *r ,int *sa ,int n ,int m){
int i,k,p,*x=wa,*y=wb ;
for(i=0; i<m; i++) cn[i] = 0;
for(i=0; i<n; i++) cn[x[i]=r[i]]++ ;
for(i=1; i<m ;i++) cn[i] += cn[i-1] ;
for(i=n-1 ;i>=0 ;i--) sa[ --cn[x[i]] ] = i ;
for(k=1,p=1 ;p<n; k<<=1,m=p) {
for(i=n-k , p=0 ;i<n;i++) y[p++] = i ;
for(i=0; i<n ;i++) if(sa[i]>=k) y[p++] = sa[i] - k ;
for(i=0 ;i<n; i++) ky[i] = x[ y[i] ] ;
for(i=0; i<m; i++) cn[i] = 0;
for(i=0 ;i<n; i++) cn[ky[i]] ++ ;
for(i=1; i<m; i++) cn[i] += cn[i-1] ;
for(i=n-1 ;i>=0 ;i--) sa[ --cn[ky[i]] ]= y[i] ;
for(swap(x,y),p=1,x[sa[0]]=0 ,i=1 ; i<n; i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],k) ? p-1 : p++ ;
}
}
void cal_height(int *r,int n){
int k=0 ;
for(int i=0; i<n; i++) rank[sa[i]] = i ;
for(int i=0; i<n; i++) {
if(k) k-- ;
int j=sa[rank[i]-1] ;
while(r[i+k] == r[j+k]) k++ ;
height[rank[i]] = k;
}
}
int main()
{
int n = 0 , mz = 'z'+1 ;
for(int i=1; i<=2;i++) {
gets(buf);
for(int j=0; buf[j] ; j++){
id[n] = i ;
r[n++] = buf[j] ;
}
id[n] = i ;
r[n++] = mz++ ;
}
id[n] = -1 ;
r[n++] = 0;
build_sa(r , sa, n , mz) ;
cal_height(r , n) ;
int ans = 0;
for(int i=2; i<n; i++) if(id[sa[i]]-id[sa[i-1]]){
ans = max(ans , height[i]) ;
}
printf("%d\n" , ans) ;
return 0;
}
5.POJ 3261 Milk Patterns(论文2.21 单个字符串 可重叠的 k 次最长重复子串)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 20050 ;
int N , K ;
struct Node{int v ,id ; };
bool cmp_v(const Node &a , const Node&b){return a.v<b.v; }
Node DT[maxn] ;
int r[maxn],wa[maxn] ,wb[maxn],ky[maxn],cn[maxn];
int sa[maxn],rank[maxn],height[maxn];
inline bool cmp(int *r,int a,int b,int l){
return r[a]==r[b] && r[a+l]==r[b+l] ;
}
void build_sa(int *r,int *sa,int n,int m){
int i,k,p,*x=wa,*y=wb ;
for(i=0;i<m;i++) cn[i]=0;
for(i=0;i<n;i++) cn[ x[i]=r[i] ]++;
for(i=1;i<m;i++) cn[i]+=cn[i-1] ;
for(i=n-1;i>=0;i--) sa[--cn[x[i]] ] = i;
for(k=1,p=1; p<n; k<<=1,m=p){
for(i=n-k,p=0;i<n;i++) y[p++] = i;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++] = sa[i]-k;
for(i=0;i<n;i++) ky[i] = x[y[i]] ;
for(i=0;i<m;i++) cn[i] =0;
for(i=0;i<n;i++) cn[ky[i]]++;
for(i=1;i<m;i++) cn[i]+=cn[i-1];
for(i=n-1;i>=0;i--) sa[--cn[ky[i]] ] = y[i] ;
for(swap(x,y),x[sa[0]]=0,i=1,p=1; i<n;i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],k) ? p-1 : p++ ;
}
}
void cal_height(int *r,int n){
for(int i=0;i<n;i++) rank[sa[i]] = i ;
int k=0;
for(int i=0;i<N;i++){
if(k) k-- ;
int j=sa[rank[i]-1] ;
while(r[i+k] == r[j+k]) k++ ;
height[rank[i]] = k ;
}
}
bool check(int len) {
int beg = 1 ;
for(int i=2;i<N;i++) {
for(;i<N && height[i]>=len;i++) ;
if(i-beg >=K) return true ;
beg = i ;
}
return false ;
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d" ,&N , &K) ;
for(int i=0; i<N; i++) scanf("%d",&DT[i].v) , DT[i].id = i;
sort(DT,DT+N,cmp_v);
ky[0]=1;
int i,p;
for(i=1,p=2; i<N;i++) ky[i] = DT[i].v==DT[i-1].v ? p-1 : p++ ;
for(i=0;i<N;i++) r[DT[i].id] = ky[i];
r[N++]=0;
build_sa(r,sa,N,p);
cal_height(r ,N) ;
int L = 0 , R = N ;
while(L<R){
int mid = L + (R-L+1)/2 ;
if(check(mid)) L = mid ;
else R = mid-1 ;
}
printf("%d\n" , L);
return 0;
}
6. POJ 3294 Life Forms (和UVA 11107 是同一题,原来写法TLE,重写了一份)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
const int maxn = 110 * 1011 ;
char buf[maxn] ;
int r[maxn] ;
int sa[maxn], height[maxn] ,rank[maxn] , id[maxn] ;
int wa[maxn] ,wb[maxn], ky[maxn], cn[maxn] ;
inline bool cmp(int *r ,int a,int b,int l){
return r[a]==r[b] && r[a+l] == r[b+l] ;
}
void build_sa(int *r, int *sa ,int n , int m){
int i, k , p , *x=wa ,*y = wb;
for(i=0; i<m; i++) cn[i] = 0;
for(i=0; i<n; i++) cn[ x[i] = r[i] ] ++ ;
for(i=1; i<m; i++) cn[i] += cn[i-1] ;
for(i=n-1; i>=0; i--) sa[ --cn[ x[i] ] ] = i ;
for(k=1,p=1; p<n; k<<=1 , m=p) {
for(p=0,i=n-k; i<n; i++) y[p++] = i ;
for(i=0; i<n; i++) if(sa[i] >=k ) y[p++] = sa[i] - k ;
for(i=0; i<n; i++) ky[i] = x[ y[i] ] ;
for(i=0; i<m; i++) cn[i] = 0;
for(i=0; i<n; i++) cn[ky[i]]++ ;
for(i=1; i<m; i++) cn[i] += cn[i-1] ;
for(i=n-1; i>=0; i--) sa[ --cn[ky[i]] ] = y[i] ;
for(swap(x ,y),p=1,x[sa[0]]=0,i=1; i<n; i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],k) ? p-1 : p++ ;
}
return ;
}
void get_height(int *s, int n) {
int i, j , k=0;
for(i=0; i<n; i++) rank[sa[i]] = i ;
for(i=0; i<n-1; i++) {
if(k) k-- ;
j = sa[rank[i]-1] ;
while(s[i+k] == s[j+k]) k++ ;
height[rank[i]] = k;
}
}
int INC = 1;
int flag[maxn] ;
bool check(int n ,int m, int mid) {
INC += 110 ;
int cnt = 1 ; flag[ id[sa[1]] ] = INC ;
for(int i=2; i<n; i++) {
while(i<n && height[i] >= mid) {
int who = id[sa[i]] ;
if(flag[who] != INC) flag[who]=INC , cnt++ ;
i++ ;
}
if(cnt*2 > m) return true ;
INC += 110 , cnt = 1 ;
flag[id[sa[i]]] = INC ;
}
return false ;
}
void print(int n, int m, int p) {
INC += 110 ;
int cnt = 1 ; flag[ id[sa[1]] ] = INC ;
for(int i=2; i<n; i++) {
while(i<n && height[i] >= p) {
int who = id[sa[i]] ;
if(flag[who] != INC) flag[who]=INC , cnt++ ;
i++ ;
}
if(cnt*2 > m) {
int a = sa[i-1] ;
for(int j=0; j<p ;j++) putchar(r[a+j]) ;
puts("") ;
}
INC += 110 , cnt = 1 ;
flag[id[sa[i]]] = INC ;
}
}
int main()
{
int m , first = 1 ;
while(scanf("%d" ,&m)==1 && m) { getchar() ;
if(!first) puts("") ; first = 0;
int n = 0;
for(int i=1; i<=m; i++) {
gets(buf);
for(int j=0; buf[j] ; j++) {
id[n]=i;
r[n++] = buf[j] ;
}
id[n] = i;
r[n++] = 'z' + i ;
}
if( m==1 ){
puts(buf) ;
continue ;
}
id[n] = m+1 , r[n++] = 0 ;
build_sa(r , sa , n, 'z'+m+2) ;
get_height(r , n) ;
if(!check(n , m , 1)) {
puts("?") ;
continue ;
}
int L = 1 , R = 1000;
while(L<R) {
int mid = L + (R-L+1)/2 ;
if(check(n , m, mid)) L = mid ;
else R = mid -1 ;
}
print(n ,m ,L) ;
}
return 0;
}
7 . POJ 3415 Common Substrings (论文2.3.2 两个字符串 长度不小于 k 的公共子串的个数 , 单调栈优化)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int maxn = 200050 ;
typedef long long LL;
int K ;
char buf[maxn] ;
int r[maxn] ,wa[maxn],wb[maxn],ky[maxn],cn[maxn];
int height[maxn],rank[maxn],sa[maxn],id[maxn];
inline bool cmp(int *r,int a,int b , int l){
return r[a]==r[b] && r[a+l]==r[b+l] ;
}
void build_sa(int *r,int *sa,int n,int m){
int i,k,p,*x=wa,*y=wb ;
for(i=0;i<m;i++) cn[i] = 0;
for(i=0;i<n;i++) cn[x[i]=r[i]]++ ;
for(i=1;i<m;i++) cn[i]+=cn[i-1];
for(i=n-1;i>=0;i--) sa[ --cn[x[i]] ] = i ;
for(k=1,p=1 ;p<n; k<<=1 , m=p){
for(i=n-k,p=0; i<n; i++) y[p++] = i;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++] = sa[i]-k;
for(i=0;i<n;i++) ky[i] = x[y[i]] ;
for(i=0;i<m;i++) cn[i] = 0;
for(i=0;i<n;i++) cn[ky[i]]++ ;
for(i=1;i<m;i++) cn[i]+=cn[i-1];
for(i=n-1;i>=0;i--) sa[ --cn[ky[i]] ] = y[i] ;
for(swap(x,y),x[sa[0]]=0,p=1,i=1; i<n; i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],k) ? p-1 : p++ ;
}
}
void cal_height(int *r ,int n){
for(int i=0;i<n;i++) rank[sa[i]] = i;
int k=0 ;
for(int i=0;i<n;i++) {
if(k) k-- ;
int j=sa[rank[i]-1] ;
while(r[i+k]==r[j+k]) k++ ;
height[rank[i]] = k ;
}
}
int h[maxn],cnt[maxn],top ;
LL cal_ans(int n, int p ,int q){
LL ans = 0;
LL sum = top = 0;
for(int i=2; i<n; i++){
for(; i<n && height[i]>=K;i++){
int _cnt = 0;
for(;top>0 && height[i]<h[top];top--) {
_cnt += cnt[top] ;
sum -= (LL) cnt[top] * (h[top]+1-K);
}
if(id[sa[i-1]] == p || _cnt>0) {
cnt[++top] = _cnt + ( id[sa[i-1]]==p ? 1 : 0) ;
h[top] = height[i] ;
sum += (LL) cnt[top] * ( h[top]+1-K) ;
}
if(id[sa[i]]==q ) {
ans += sum ;
}
}
sum = top = 0;
}
return ans ;
}
int main()
{
while(scanf("%d",&K)==1 && K){
int mz = 'z'+1 , n = 0 ;
scanf("%s",buf);
for(int i=0;buf[i];i++) id[n]=1 ,r[n++]=buf[i] ;
id[n]=0,r[n++]=mz++ ;
scanf("%s" ,buf) ;
for(int i=0;buf[i];i++) id[n] = 2 ,r[n++] = buf[i];
id[n] = 0 , r[n++] = 0 ;
build_sa(r,sa,n,mz);
cal_height(r,n);
LL ans = 0;
ans += cal_ans(n,1,2);
ans += cal_ans(n,2,1);
printf("%I64d\n" , ans);
}
return 0 ;
}
8. POJ 3693 Maximum repetition substring(论文2.2.4 单个字符串 重复次数最多的连续重复子串)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100050 ;
int r[maxn] ; char buf[maxn] ;
int wa[maxn] ,wb[maxn],ky[maxn] , cn[maxn] ;
int height[maxn], rank[maxn] ,sa[maxn] ;
inline bool cmp(int *r,int a,int b,int l){
return r[a]==r[b] && r[a+l]==r[b+l] ;
}
void build_sa(int *r,int *sa,int n,int m){
int i,k,p,*x=wa,*y=wb;
for(i=0;i<m;i++) cn[i] = 0;
for(i=0;i<n;i++) cn[x[i]=r[i]]++ ;
for(i=1;i<m;i++) cn[i] += cn[i-1];
for(i=n-1;i>=0;i--) sa[--cn[x[i]] ] = i;
for(k=1,p=1 ;p<n;k<<=1 , m=p){
for(i=n-k,p=0 ; i<n ;i++) y[p++]= i ;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++] = sa[i] - k ;
for(i=0;i<n; i++) ky[i] = x[y[i]] ;
for(i=0;i<m;i++) cn[i] = 0 ;
for(i=0;i<n;i++) cn[ky[i]] ++ ;
for(i=1;i<m;i++) cn[i] += cn[i-1] ;
for(i=n-1;i>=0;i--) sa[ --cn[ky[i]] ] = y[i] ;
for(swap(x,y),x[sa[0]]=0,i=p=1; i<n;i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],k) ? p-1 : p++ ;
}
}
void cal_height(int *r,int n){
for(int i=0;i<n;i++) rank[sa[i]] = i;
int k =0 ;
for(int i=0; i<n; i++) {
if(k) k-- ;
int j=sa[rank[i]-1] ;
while(r[i+k] == r[j+k]) k++ ;
height[rank[i]] = k ;
}
}
int Log[maxn];
int best[20][maxn];
int rmq[maxn][20] ;
void rmq_init(int n){
for(int i=0; i<n; i++) rmq[i][0] = height[i] ;
for(int j=1; (1<<j)<=n; j++)
for(int i=0; i+(1<<j)-1 <n ; i++)
rmq[i][j] = min(rmq[i][j-1] , rmq[i+(1<<(j-1))][j-1]) ;
}
inline int ask(int L,int R){
int t = Log[R-L+1] ;
return min(rmq[L][t] , rmq[R-(1<<t)+1][t]) ;
}
inline int lcp(int a,int b){
a = rank[a] , b=rank[b];
if(a>b) swap(a,b) ;
return ask(a+1,b);
}
void cal_ans(int n){
n-- ;
int max_rep=0 , len , ans_beg , ans_len ;
for(int L=1; L<n; L++){
if(L * max_rep >= n) break ;
for(int i=0; i+L<n ;i+=L){
int k = lcp(i , i+L) ;
int tmp = k / L ;
int ii = i - (L - k%L);
if(ii>=0 && lcp(ii , ii+L) >= L-k%L) tmp++ ;
tmp++ ;
if(tmp > max_rep) max_rep = tmp , len = L ;
}
}
ans_beg = -1 , ans_len = max_rep * len ;
for(int i=0; i+ans_len-1 < n; i++) {
if(lcp(i , i+len) >= ans_len - len) {
if(ans_beg == -1) ans_beg = i ;
else if(rank[i] < rank[ans_beg]) ans_beg = i ;
}
}
for(int i=ans_beg ; i<ans_beg + ans_len ;i++) putchar(buf[i]) ;
puts("") ;
}
int main()
{
// freopen("in.txt","r",stdin);
Log[0] = -1;
for(int i=1;i<maxn;i++){
Log[i]=(i&(i-1))?Log[i-1]:Log[i-1] + 1 ;
}
int cas = 1 ;
while(gets(buf) && buf[0]!='#'){
int n = 0;
for(int i=0; buf[i]; i++) r[n++] = buf[i] ;
r[n++] = 0 ;
build_sa(r ,sa ,n ,'z'+1);
cal_height(r ,n) ;
rmq_init(n) ;
printf("Case %d: " , cas++) ;
cal_ans(n) ;
}
return 0;
}
9. SPOJ DISUBSTR Distinct Substrings(论文2.2.2 单个字符串 不相同子串个数)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1010 ;
char r[maxn] ;
int wa[maxn] , wb[maxn] ,ky[maxn] , cn[maxn];
int height[maxn] , rank[maxn] , sa[maxn];
inline bool cmp(int *r,int a,int b,int l){
return r[a]==r[b] && r[a+l]==r[b+l] ;
}
void build_sa(char *r ,int *sa ,int n ,int m){
int i, k , p ,*x =wa ,*y = wb ;
for(i=0; i<m; i++) cn[i]= 0 ;
for(i=0; i<n; i++) cn[x[i]=r[i]]++ ;
for(i=1; i<m; i++) cn[i] += cn[i-1] ;
for(i=n-1 ;i>=0 ;i--) sa[--cn[x[i]]] = i ;
for(k=p=1; p<n ;m=p , k<<=1){
for(p=0,i=n-k;i<n;i++) y[p++] = i ;
for(i=0;i<n;i++) if(sa[i] >= k) y[p++] = sa[i] - k ;
for(i=0;i<n;i++) ky[i] = x[y[i]] ;
for(i=0;i<m;i++) cn[i] = 0;
for(i=0;i<n;i++) cn[ky[i]] ++ ;
for(i=1;i<m;i++) cn[i] += cn[i-1] ;
for(i=n-1 ;i>=0; i--) sa[--cn[ky[i]]] = y[i];
for(swap(x,y),x[sa[0]]=0 , i=p=1;i<n;i++)
x[sa[i]] = cmp(y ,sa[i-1] ,sa[i] ,k) ? p-1 : p++ ;
}
}
void cal_height(char *r , int n){
for(int i=0;i<n;i++) rank[sa[i]] = i ;
int k=0;
for(int i=0;i<n;i++){
if(k) k-- ;
int j = sa[rank[i]-1] ;
while(r[i+k] == r[j+k]) k++ ;
height[rank[i]] = k ;
}
}
int cal_ans(int n){
n-- ;
int ans = 0 ;
for(int i=1; i<=n; i++) {
ans += n -sa[i] - height[i] ;
}
return ans ;
}
int main()
{
int T;
scanf("%d" ,&T) ;
while(T--) {
scanf("%s" ,r) ;
int n = strlen(r)+1 ;
build_sa(r ,sa ,n , 'z'+1) ;
cal_height(r , n);
int ans = cal_ans(n) ;
printf("%d\n" ,ans) ;
}
return 0;
}
10. SPOJ PHRASES Relevant Phrases of Annihilation(多个字符串 每个字符串至少出现两次且不重叠的最长子串)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 1e6 ;
const int maxn = 100050 ;
char buf[maxn];
int r[maxn] ,wa[maxn],wb[maxn] ,ky[maxn] ,cn[maxn] ;
int height[maxn],rank[maxn],sa[maxn] ,id[maxn] ;
inline bool cmp(int *r,int a,int b,int l){
return r[a]==r[b] && r[a+l]==r[b+l] ;
}
void build_sa(int *r,int *sa,int n,int m){
int i,k,p,*x=wa,*y=wb;
for(i=0;i<m;i++) cn[i] = 0;
for(i=0;i<n;i++) cn[x[i]=r[i]]++ ;
for(i=1;i<m;i++) cn[i] += cn[i-1];
for(i=n-1;i>=0;i--) sa[--cn[x[i]] ] = i;
for(k=1,p=1 ;p<n;k<<=1 , m=p){
for(i=n-k,p=0 ; i<n ;i++) y[p++]= i ;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++] = sa[i] - k ;
for(i=0;i<n; i++) ky[i] = x[y[i]] ;
for(i=0;i<m;i++) cn[i] = 0 ;
for(i=0;i<n;i++) cn[ky[i]] ++ ;
for(i=1;i<m;i++) cn[i] += cn[i-1] ;
for(i=n-1;i>=0;i--) sa[ --cn[ky[i]] ] = y[i] ;
for(swap(x,y),x[sa[0]]=0,i=p=1; i<n;i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],k) ? p-1 : p++ ;
}
}
void cal_height(int *r,int n){
for(int i=0;i<n;i++) rank[sa[i]] = i;
int k =0 ;
for(int i=0; i<n; i++) {
if(k) k-- ;
int j=sa[rank[i]-1] ;
while(r[i+k] == r[j+k]) k++ ;
height[rank[i]] = k ;
}
}
int mi[12] , ma[12] , cnt[12] ;
void init_check(){
for(int i=0; i<12; i++) mi[i] = INF , ma[i]=-INF ,cnt[i] = 0;
}
bool check(int len ,int n , int N){
init_check();
int p = sa[1] ;
mi[id[p]] = min(mi[id[p]] , sa[1]) ;
ma[id[p]] = max(ma[id[p]] , sa[1]) ;
cnt[id[p]]++ ;
for(int i=2; i<n; i++){
for(;i<n && height[i]>=len; i++){
int p = sa[i] ;
mi[id[p]] = min(mi[id[p]] , p) ;
ma[id[p]] = max(ma[id[p]] , p) ;
cnt[id[p]]++ ;
}
bool ok = true ;
for(int j=1;j<=N;j++) {
if(ma[j] - mi[j] < len || cnt[j]<2) {ok=false ; break; }
}
if(ok) return true ;
init_check() ;
int p = sa[i] ;
mi[id[p]] = min(mi[id[p]] , p) ;
ma[id[p]] = max(ma[id[p]] , p) ;
cnt[id[p]]++ ;
}
return false ;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
int n = 0 , N , mz ='z'+1 , Mlen =0 ;
scanf("%d" ,&N); gets(buf) ;
for(int i=1;i<=N;i++){
gets(buf) ;
int j;
for(j=0; buf[j] ;j++) if(buf[j]>='a' && buf[j]<='z') {
id[n]=i ;
r[n++] = buf[j] ;
}
Mlen = max(Mlen , j);
id[n] = 0;
r[n++] = mz++;
}
id[n] = 0 , r[n++] = 0 ;
build_sa(r,sa,n,mz) ;
cal_height(r,n) ;
int L = 0 , R = Mlen ;
while(L<R){
int mid = L + (R-L+1)/2 ;
if(check(mid , n ,N)) L = mid ;
else R = mid - 1 ;
}
printf("%d\n" , L) ;
}
return 0;
}
11. SPOJ REPEATS Repeats(重复次数最多的连续重复子串)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100050 ;
int r[maxn] ; char buf[maxn] ;
int wa[maxn] ,wb[maxn],ky[maxn] , cn[maxn] ;
int height[maxn], rank[maxn] ,sa[maxn] ;
inline bool cmp(int *r,int a,int b,int l){
return r[a]==r[b] && r[a+l]==r[b+l] ;
}
void build_sa(int *r,int *sa,int n,int m){
int i,k,p,*x=wa,*y=wb;
for(i=0;i<m;i++) cn[i] = 0;
for(i=0;i<n;i++) cn[x[i]=r[i]]++ ;
for(i=1;i<m;i++) cn[i] += cn[i-1];
for(i=n-1;i>=0;i--) sa[--cn[x[i]] ] = i;
for(k=1,p=1 ;p<n;k<<=1 , m=p){
for(i=n-k,p=0 ; i<n ;i++) y[p++]= i ;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++] = sa[i] - k ;
for(i=0;i<n; i++) ky[i] = x[y[i]] ;
for(i=0;i<m;i++) cn[i] = 0 ;
for(i=0;i<n;i++) cn[ky[i]] ++ ;
for(i=1;i<m;i++) cn[i] += cn[i-1] ;
for(i=n-1;i>=0;i--) sa[ --cn[ky[i]] ] = y[i] ;
for(swap(x,y),x[sa[0]]=0,i=p=1; i<n;i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],k) ? p-1 : p++ ;
}
}
void cal_height(int *r,int n){
for(int i=0;i<n;i++) rank[sa[i]] = i;
int k =0 ;
for(int i=0; i<n; i++) {
if(k) k-- ;
int j=sa[rank[i]-1] ;
while(r[i+k] == r[j+k]) k++ ;
height[rank[i]] = k ;
}
}
int Log[maxn];
int best[20][maxn];
int rmq[maxn][20] ;
void rmq_init(int n){
for(int i=0; i<n; i++) rmq[i][0] = height[i] ;
for(int j=1; (1<<j)<=n; j++)
for(int i=0; i+(1<<j)-1 <n ; i++)
rmq[i][j] = min(rmq[i][j-1] , rmq[i+(1<<(j-1))][j-1]) ;
}
inline int ask(int L,int R){
int t = Log[R-L+1] ;
return min(rmq[L][t] , rmq[R-(1<<t)+1][t]) ;
}
inline int lcp(int a,int b){
a = rank[a] , b=rank[b];
if(a>b) swap(a,b) ;
return ask(a+1,b);
}
void cal_ans(int n){
n-- ;
int max_rep=0 ;
for(int L=1; L<n; L++){
if(L * max_rep >= n) break ;
for(int i=0; i+L<n ;i+=L){
int k = lcp(i , i+L) ;
int tmp = k / L ;
int ii = i - (L - k%L);
if(ii>=0 && lcp(ii , ii+L) >= L-k%L) tmp++ ;
tmp++ ;
if(tmp > max_rep) max_rep = tmp ;
}
}
printf("%d\n" , max_rep) ;
}
int main()
{
// freopen("in.txt","r",stdin);
Log[0] = -1;
for(int i=1;i<maxn;i++){
Log[i]=(i&(i-1))?Log[i-1]:Log[i-1] + 1 ;
}
int T ;
scanf("%d" ,&T) ;
while(T--){
int n ;
scanf("%d" , &n);
for(int i=0; i<n; i++) scanf("%s" ,buf) , r[i] = buf[0] ;
r[n++] = 0 ;
build_sa(r ,sa ,n ,'z'+1);
cal_height(r ,n) ;
rmq_init(n) ;
cal_ans(n) ;
}
return 0;
}
12 . URAL 1297Palindrome (最长回文子串)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 2050;
char buf[maxn] ;
int r[maxn],pos[maxn], N;
int wa[maxn],wb[maxn],ky[maxn],cn[maxn];
int sa[maxn],rank[maxn],height[maxn];
inline bool cmp(int *r,int a,int b,int l){
return r[a]==r[b] && r[a+l] == r[b+l] ;
}
void build_sa(int *r,int *sa,int n,int m){
int i,k,p,*x=wa,*y=wb ;
for(i=0;i<m;i++) cn[i]= 0;
for(i=0;i<n;i++) cn[x[i]=r[i]] ++ ;
for(i=1;i<m;i++) cn[i]+=cn[i-1];
for(i=n-1;i>=0;i--) sa[--cn[x[i]]] = i ;
for(k=p=1 ;p<n; k<<=1 , m=p){
for(i=n-k,p=0; i<n; i++) y[p++] = i ;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++] = sa[i]- k;
for(i=0;i<n;i++) ky[i] = x[y[i]] ;
for(i=0;i<m;i++) cn[i] = 0;
for(i=0;i<n;i++) cn[ky[i]]++ ;
for(i=1;i<m;i++) cn[i] += cn[i-1] ;
for(i=n-1;i>=0;i--) sa[--cn[ky[i]]] = y[i] ;
for(swap(x,y),x[sa[0]]=0 , i=p=1; i<n;i++)
x[sa[i]] = cmp(y , sa[i-1] ,sa[i] , k) ? p-1 : p++ ;
}
}
void cal_height(int *r,int n){
for(int i=0;i<n;i++) rank[sa[i]] = i ;
int k=0;
for(int i=0;i<n;i++) {
if(k) k-- ;
int j= sa[rank[i]-1] ;
while(r[i+k] == r[j+k])
k++ ;
height[rank[i]] = k ;
}
}
int rmq[maxn][20] ;
void init_rmq(int n){
for(int i=0; i<n; i++) rmq[i][0] = height[i] ;
for(int j=1;(1<<j)<=n; j++){
for(int i=0; i+(1<<j)-1<n ;i++){
rmq[i][j] = min(rmq[i][j-1] , rmq[i+(1<<j>>1)][j-1]) ;
}
}
}
int ask(int L,int R){
int k = 0 ;
while((1<<(k+1)) <= R-L+1 ) k++ ;
return min(rmq[L][k] , rmq[R-(1<<k)+1][k]) ;
}
int lcp(int a , int b){
a = rank[a] , b = rank[b] ;
if(a > b) swap(a ,b) ;
return ask(a+1 , b) ;
}
void cal_ans(int n){
int p = 0 , M = 0 ;
for(int i=0 ; i<N; i++){
int tmp = lcp(i , N*2-i+1) ;
if(tmp*2 > M) M = tmp*2 , p = i - tmp ;
tmp = lcp(i , N*2-i) ;
if(tmp*2-1 > M) M = tmp*2-1 , p = i - tmp + 1 ;
}
buf[p+M] = 0 ;
printf("%s\n" , buf+p) ;
}
int main()
{
while(scanf("%s" ,buf)!=EOF){
N= strlen(buf) ;
int n = 0 , mz = 'z'+1 ;
for(int i = 0 ; i<N; i++){
pos[n] = i ;
r[n++] = buf[i] ;
}
pos[n]=-1 , r[n++] = mz++ ;
for(int i=N-1 ; i>=0 ;i--){
pos[n] = i ;
r[n++]=buf[i] ;
}
pos[n]=-1, r[n++] = 0 ;
build_sa(r,sa,n,mz) ;
cal_height(r,n);
init_rmq(n) ;
cal_ans(n) ;
}
return 0;
}
13. URAL 1517 Freedom of Choice (最长公共子序列)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 200050 ;
char buf[maxn] ;
int r[maxn] , N ;
int wa[maxn],wb[maxn],ky[maxn],cn[maxn];
int sa[maxn],rank[maxn],height[maxn];
inline bool cmp(int *r,int a,int b,int l){
return r[a]==r[b] && r[a+l] == r[b+l] ;
}
void build_sa(int *r,int *sa,int n,int m){
int i,k,p,*x=wa,*y=wb ;
for(i=0;i<m;i++) cn[i]= 0;
for(i=0;i<n;i++) cn[x[i]=r[i]] ++ ;
for(i=1;i<m;i++) cn[i]+=cn[i-1];
for(i=n-1;i>=0;i--) sa[--cn[x[i]]] = i ;
for(k=p=1 ;p<n; k<<=1 , m=p){
for(i=n-k,p=0; i<n; i++) y[p++] = i ;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++] = sa[i]- k;
for(i=0;i<n;i++) ky[i] = x[y[i]] ;
for(i=0;i<m;i++) cn[i] = 0;
for(i=0;i<n;i++) cn[ky[i]]++ ;
for(i=1;i<m;i++) cn[i] += cn[i-1] ;
for(i=n-1;i>=0;i--) sa[--cn[ky[i]]] = y[i] ;
for(swap(x,y),x[sa[0]]=0 , i=p=1; i<n;i++)
x[sa[i]] = cmp(y , sa[i-1] ,sa[i] , k) ? p-1 : p++ ;
}
}
void cal_height(int *r,int n){
for(int i=0;i<n;i++) rank[sa[i]] = i ;
int k=0;
for(int i=0;i<n;i++) {
if(k) k-- ;
int j= sa[rank[i]-1] ;
while(r[i+k] == r[j+k])
k++ ;
height[rank[i]] = k ;
}
}
void cal_ans(int n){
int M = 0 , p = 0 ;
for(int i=2; i<n; i++) {
if( (sa[i-1]<N) != (sa[i]<N) ) {
if(height[i] > M) M = height[i] , p = max( sa[i] , sa[i-1] ) ;
}
}
p-=N+1 ;
buf[p+M] = 0 ; //cout<<M<<" "<<p<<endl ;
printf("%s\n" , buf+p);
}
int main()
{
int mz = 'z'+1 , n = 0;
scanf("%d" ,&N) ;
scanf("%s" ,buf) ;
for(int i=0;i<N;i++) r[n++] = buf[i] ;
scanf("%s" ,buf) ;
r[n++] = mz++ ;
for(int i=0;i<N;i++) r[n++] = buf[i] ;
r[n++] = 0 ;
build_sa(r ,sa,n,mz) ;
cal_height(r , n) ;
cal_ans(n);
return 0;
}
14. 敲完收工。