题意:多个字符串的最长公共子串。

解题关键:字符串的任何一个子串都是这个字符串的某个后缀的前缀。求A和B的最长公共子串等价于求A的后缀和B的后缀的最长公共前缀的最大值。

后缀数组的经典例题,连接在一起,二分长度,height数组遍历即可。

注意flag的问题,采用二分小于的方式,可能会出现有最优解但是flag为false的情况,下界需要-1,采用0,而采用等于的话,就不会出现,不过有些题会出现死循环。

还有因为多添加的符号一定不会加入vis数组,所以vis数组只需建立4000即可。

为什么两个字符串不需要二分?而多个字符串需要二分?因为 两个字符串可以直接判定height[i]是属于两个字符串的最大公共子串,而多个必须通过vis数组判定。

法一:

 #include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
const int N=;
int r[N],id[N];
char tmp[],ans[];
bool vis[]; int wa[N],wb[N],wv[N],wc[N],n,m;
bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
void make_sa(int *r,int *sa,int n,int m){
int i,j,p,*x=wa,*y=wb;
for(i=;i<m;i++) wc[i]=;
for(i=;i<n;i++) wc[x[i]=r[i]]++;
for(i=;i<m;i++) wc[i]+=wc[i-];
for(i=n-;i>=;i--) sa[--wc[x[i]]]=i;
for(j=,p=;p<n;j*=,m=p){
for(p=,i=n-j;i<n;i++) y[p++]=i;
for(i=;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=;i<n;i++) wv[i]=x[y[i]];
for(i=;i<m;i++) wc[i]=;
for(i=;i<n;i++) wc[wv[i]]++;
for(i=;i<m;i++) wc[i]+=wc[i-];
for(i=n-;i>=;i--) sa[--wc[wv[i]]]=y[i];
for(swap(x,y),p=,x[sa[]]=,i=;i<n;i++) x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
}
return;
}
int rank1[N],height[N],sa[N];
void make_height(int *r,int *sa,int n){
int i,j,k=;
for(i=;i<=n;i++) rank1[sa[i]]=i;
for(i=;i<n;height[rank1[i++]]=k)
for(k?k--:,j=sa[rank1[i]-];r[i+k]==r[j+k];k++);
return;
} bool check(int x){
memset(vis,,sizeof vis);
int cnt=;
for(int i=;i<=n;i++){
if(height[i]<x){
memset(vis,,sizeof vis);
cnt=;
continue;
}
if(!vis[id[sa[i-]]]) vis[id[sa[i-]]]=true,cnt++;
if(!vis[id[sa[i]]]) vis[id[sa[i]]]=true,cnt++;
if(cnt==m){
for(int j=;j<x;j++) ans[j]=r[sa[i]+j]+'a'-;ans[x]=;
return true;
}
}
return false;
} bool erfen(int l,int r){
bool flag=false;
while(l<r){
int mid=(l+r+)>>;
if(check(mid)) l=mid,flag=true;
else r=mid-;
}
return flag;
} int main() {
while(scanf("%d",&m)&&m){
n=;
int temp=;
for(int i=;i<=m;i++){
scanf("%s",tmp);
int siz=strlen(tmp);
for(int j=;j<siz;j++) id[n]=i,r[n++]=tmp[j]-'a'+;
id[n]=temp;
r[n++]=temp++;
}
r[n]=;
make_sa(r,sa,n+,);
make_height(r,sa,n);
bool f=erfen(,);//为什么0可以,1不可以
if(f) printf("%s\n",ans);
else printf("IDENTITY LOST\n");
}
}

法二:

 #include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
const int N=;
int r[N],id[N];
char tmp[],ans[];
bool vis[]; int wa[N],wb[N],wv[N],wc[N],n,m;
bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
void make_sa(int *r,int *sa,int n,int m){
int i,j,p,*x=wa,*y=wb;
for(i=;i<m;i++) wc[i]=;
for(i=;i<n;i++) wc[x[i]=r[i]]++;
for(i=;i<m;i++) wc[i]+=wc[i-];
for(i=n-;i>=;i--) sa[--wc[x[i]]]=i;
for(j=,p=;p<n;j*=,m=p){
for(p=,i=n-j;i<n;i++) y[p++]=i;
for(i=;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=;i<n;i++) wv[i]=x[y[i]];
for(i=;i<m;i++) wc[i]=;
for(i=;i<n;i++) wc[wv[i]]++;
for(i=;i<m;i++) wc[i]+=wc[i-];
for(i=n-;i>=;i--) sa[--wc[wv[i]]]=y[i];
for(swap(x,y),p=,x[sa[]]=,i=;i<n;i++) x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
}
return;
}
int rank1[N],height[N],sa[N];
void make_height(int *r,int *sa,int n){
int i,j,k=;
for(i=;i<=n;i++) rank1[sa[i]]=i;
for(i=;i<n;height[rank1[i++]]=k)
for(k?k--:,j=sa[rank1[i]-];r[i+k]==r[j+k];k++);
return;
} bool check(int x){
memset(vis,,sizeof vis);
int cnt=;
for(int i=;i<=n;i++){
if(height[i]<x){
memset(vis,,sizeof vis);
cnt=;
continue;
}
if(!vis[id[sa[i-]]]) vis[id[sa[i-]]]=true,cnt++;
if(!vis[id[sa[i]]]) vis[id[sa[i]]]=true,cnt++;
if(cnt==m){
for(int j=;j<x;j++) ans[j]=r[sa[i]+j]+'a'-;ans[x]=;
return true;
}
}
return false;
} bool erfen(int l,int r){
bool flag=false;
while(l<=r){
int mid=(l+r+)>>;
if(check(mid)) l=mid+,flag=true;
else r=mid-;
}
return flag;
} int main() {
while(scanf("%d",&m)&&m){
n=;
int temp=;
for(int i=;i<=m;i++){
scanf("%s",tmp);
int siz=strlen(tmp);
for(int j=;j<siz;j++) id[n]=i,r[n++]=tmp[j]-'a'+;
id[n]=temp;
r[n++]=temp++;
}
r[n]=;
make_sa(r,sa,n+,);
make_height(r,sa,n);
bool f=erfen(,);//为什么0可以,1不可以
if(f) printf("%s\n",ans);
else printf("IDENTITY LOST\n");
}
}

dc3:依然注意是3倍的问题

 #include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int N=;
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int wa[N],wb[N],wv[N],ws1[N];
int c0(int *r,int a,int b){ return r[a]==r[b]&&r[a+]==r[b+]&&r[a+]==r[b+]; }
int c12(int k,int *r,int a,int b){
if(k==) return r[a]<r[b]||r[a]==r[b]&&c12(,r,a+,b+);
else return r[a]<r[b]||r[a]==r[b]&&wv[a+]<wv[b+];
}
void sort(int *r,int *a,int *b,int n,int m){
int i;
for(i=;i<n;i++) wv[i]=r[a[i]];
for(i=;i<m;i++) ws1[i]=;
for(i=;i<n;i++) ws1[wv[i]]++;
for(i=;i<m;i++) ws1[i]+=ws1[i-];
for(i=n-;i>=;i--) b[--ws1[wv[i]]]=a[i];
return;
}
void dc3(int *r,int *sa,int n,int m){
int i,j,*rn=r+n,*san=sa+n,ta=,tb=(n+)/,tbc=,p;
r[n]=r[n+]=;
for(i=;i<n;i++) if(i%!=) wa[tbc++]=i;
sort(r+,wa,wb,tbc,m);
sort(r+,wb,wa,tbc,m);
sort(r,wa,wb,tbc,m);
for(p=,rn[F(wb[])]=,i=;i<tbc;i++)
rn[F(wb[i])]=c0(r,wb[i-],wb[i])?p-:p++;
if(p<tbc) dc3(rn,san,tbc,p);
else for(i=;i<tbc;i++) san[rn[i]]=i;
for(i=;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*;
if(n%==) wb[ta++]=n-;
sort(r,wb,wa,ta,m);
for(i=;i<tbc;i++) wv[wb[i]=G(san[i])]=i;
for(i=,j=,p=;i<ta && j<tbc;p++)
sa[p]=c12(wb[j]%,r,wa[i],wb[j])?wa[i++]:wb[j++];
for(;i<ta;p++) sa[p]=wa[i++];
for(;j<tbc;p++) sa[p]=wb[j++];
return;
}
int rank1[N],height[N],sa[*N];
void make_height(int *r,int *sa,int n){
int i,j,k=;
for(i=;i<=n;i++) rank1[sa[i]]=i;
for(i=;i<n;height[rank1[i++]]=k)
for(k?k--:,j=sa[rank1[i]-];r[i+k]==r[j+k];k++);
return;
}
int r[*N],id[N],n,m;
char tmp[],ans[];
bool vis[]; bool check(int x){
memset(vis,,sizeof vis);
int cnt=;
for(int i=;i<=n;i++){
if(height[i]<x){
memset(vis,,sizeof vis);
cnt=;
continue;
}
if(!vis[id[sa[i-]]]) vis[id[sa[i-]]]=true,cnt++;
if(!vis[id[sa[i]]]) vis[id[sa[i]]]=true,cnt++;
if(cnt==m){
for(int j=;j<x;j++) ans[j]=r[sa[i]+j]+'a'-;ans[x]=;
return true;
}
}
return false;
} bool erfen(int l,int r){
bool flag=false;
while(l<r){
int mid=(l+r+)>>;
if(check(mid)) l=mid,flag=true;
else r=mid-;
}
return flag;
} int main() {
while(scanf("%d",&m)&&m){
n=;
int temp=;
for(int i=;i<=m;i++){
scanf("%s",tmp);
int siz=strlen(tmp);
for(int j=;j<siz;j++) id[n]=i,r[n++]=tmp[j]-'a'+;
id[n]=temp;
r[n++]=temp++;
}
r[n]=;
dc3(r,sa,n+,);
make_height(r,sa,n);
bool f=erfen(,);//为什么0可以,1不可以
if(f) printf("%s\n",ans);
else printf("IDENTITY LOST\n");
}
}

[poj3450]Corporate Identity(后缀数组)的更多相关文章

  1. POJ3450 Corporate Identity —— 后缀数组 最长公共子序列

    题目链接:https://vjudge.net/problem/POJ-3450 Corporate Identity Time Limit: 3000MS   Memory Limit: 65536 ...

  2. poj 3518 Corporate Identity 后缀数组->多字符串最长相同连续子串

    题目链接 题意:输入N(2 <= N <= 4000)个长度不超过200的字符串,输出字典序最小的最长公共连续子串; 思路:将所有的字符串中间加上分隔符,注:分隔符只需要和输入的字符不同, ...

  3. POJ-3450 Corporate Identity (KMP+后缀数组)

    Description Beside other services, ACM helps companies to clearly state their “corporate identity”, ...

  4. POJ3450 Corporate Identity 【后缀数组】

    Corporate Identity Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 7662   Accepted: 264 ...

  5. POJ3450 Corporate Identity

    后缀数组. 解决多个字符串的最长公共子串. 采用对长度的二分,将子串按height分组,每次判断是否在每个字符串中都出现过. 复杂度O(NlogN) By:大奕哥 #include<cstrin ...

  6. [HDU2328]Corporate Identity(后缀数组)

    传送门 求 n 个串的字典序最小的最长公共子串. 和 2 个串的处理方法差不多. 把 n 个串拼接在一起,中间连上一个没有出现过的字符防止匹配过界. 求出 height 数组后二分公共子串长度给后缀数 ...

  7. POJ3080 POJ3450Corporate Identity(广义后缀自动机||后缀数组||KMP)

    Beside other services, ACM helps companies to clearly state their “corporate identity”, which includ ...

  8. hdu2328 Corporate Identity【string库使用】【暴力】【KMP】

    Corporate Identity Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  9. kuangbin带你飞 后缀数组 题解

    2份模板 DC3 . 空间复杂度O3N 时间复杂度On #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb)) #define G(x) ((x) < ...

随机推荐

  1. onscreen and offscreen

    本文来自stackoverflow一位网友的解答,感觉非常不错就摘录了. --------------------------------------------------------------- ...

  2. 修改linux的hostname (修改linux系统的IP和hostname)

    # vi /etc/sysconfig/networkNETWORKING=yesHOSTNAME=yourname //在这修改hostnameNISDOMAIN=eng-cn.platform.c ...

  3. Python中高层次的数据结构,动态类型和动态绑定,使得它非常适合于快速应用开发,也适合于作为胶水语言连接已有的软件部件。

    https://github.com/jhao104/proxy_pool/blob/master/doc/introduce.md 3.代码模块 Python中高层次的数据结构,动态类型和动态绑定, ...

  4. regularexpression_action

    re.compile('"ssid":"[^"]*"}',re.MULTILINE) regex ,str_= re.compile('"s ...

  5. 我的Java开发学习之旅------>使用Working Setst将Eclipse中的项目分类使项目一目了然

    今天发现Eclipse中若有太多的项目,杂七杂八的,看起来会非常的痛苦.今天请教公司的前辈学会了一个方法,在Eclipse中,当项目比较多的时候,我们可以用WorkingSet将这些项目分类,把相关连 ...

  6. Linux就该这么学--Shell脚本条件语句(一)

    1.条件测试语句能够让Shell脚本根据实际工作灵活调整工作内容,例如判断系统的状态后执行指定的工作,或创建指定数量的用户,批量修改用户密码,这些都可以让Shell脚本通过条件测试语句完成. if条件 ...

  7. enumerate next eval reload 内置函数的用法

    enumerate next eval reload 内置函数的用法 #enumerate() 函数用于将一个可遍历的数据对象(如列表.元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用 ...

  8. SAP采购寄售业务操作步骤

    [转自 http://blog.sina.com.cn/s/blog_6466e5f70100jghg.html] 这里所示的是比较完整的步骤,包含了:信息记录.采购合同.货源清单.采购申请.采购订单 ...

  9. Java性能分析方法

    Java调优经验 http://www.rowkey.me/blog/2016/11/02/java-profile/

  10. 认识与入门 Markdown

    Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用.看到这里请不要被「标记」.「语言」所迷惑,Markdown 的语法十分简单.常用的标记符号也不 ...