[poj3450]Corporate Identity(后缀数组)
题意:多个字符串的最长公共子串。
解题关键:字符串的任何一个子串都是这个字符串的某个后缀的前缀。求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(后缀数组)的更多相关文章
- POJ3450 Corporate Identity —— 后缀数组 最长公共子序列
题目链接:https://vjudge.net/problem/POJ-3450 Corporate Identity Time Limit: 3000MS Memory Limit: 65536 ...
- poj 3518 Corporate Identity 后缀数组->多字符串最长相同连续子串
题目链接 题意:输入N(2 <= N <= 4000)个长度不超过200的字符串,输出字典序最小的最长公共连续子串; 思路:将所有的字符串中间加上分隔符,注:分隔符只需要和输入的字符不同, ...
- POJ-3450 Corporate Identity (KMP+后缀数组)
Description Beside other services, ACM helps companies to clearly state their “corporate identity”, ...
- POJ3450 Corporate Identity 【后缀数组】
Corporate Identity Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 7662 Accepted: 264 ...
- POJ3450 Corporate Identity
后缀数组. 解决多个字符串的最长公共子串. 采用对长度的二分,将子串按height分组,每次判断是否在每个字符串中都出现过. 复杂度O(NlogN) By:大奕哥 #include<cstrin ...
- [HDU2328]Corporate Identity(后缀数组)
传送门 求 n 个串的字典序最小的最长公共子串. 和 2 个串的处理方法差不多. 把 n 个串拼接在一起,中间连上一个没有出现过的字符防止匹配过界. 求出 height 数组后二分公共子串长度给后缀数 ...
- POJ3080 POJ3450Corporate Identity(广义后缀自动机||后缀数组||KMP)
Beside other services, ACM helps companies to clearly state their “corporate identity”, which includ ...
- hdu2328 Corporate Identity【string库使用】【暴力】【KMP】
Corporate Identity Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- kuangbin带你飞 后缀数组 题解
2份模板 DC3 . 空间复杂度O3N 时间复杂度On #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb)) #define G(x) ((x) < ...
随机推荐
- python读写数据篇
一.读写数据1.读数据 #使用open打开文件后一定要记得调用文件对象的close()方法.比如可以用try/finally语句来确保最后能关闭文件.file_object = open('thefi ...
- phpstorm pycharm IntelliJ IDEA激活
phpstorm 和 pycharm server选项里边输入 http://idea.imsxm.com/ IntelliJ IDEA 1. 到网站 http://idea.lanyus.com/ ...
- Awesome Vue.js vue.js学习资源链接大全 中文
https://blog.csdn.net/caijunfen/article/details/78216868
- mongo-connector导入数据到Es
要求 基于mongo-connector同步数据,必须要求mongodb为复制集架构,原因是此插件是基于oplog操作记录进行数据同步的:而oplog可以说是Mongodb Replication的纽 ...
- (1)Web 应用是一个状态机,视图与状态是一一对应的。 (2)所有的状态,保存在一个对象里面。
Redux 入门教程(一):基本用法 - 阮一峰的网络日志 http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_u ...
- split_brain
脑裂 系统中两个或多个部分开始独立工作
- Git you are not allowed to push code to protected branches on this project?
error: You are not allowed to push code to protected branches on this project....error: failed to pu ...
- 您使用的是不受支持的命令行标记 chrome
检查 chrome://flags/#extensions-on-chrome-urls 是否开启 开启了的话就关掉检查 启动chrome的快捷方式是否在目标后有额外的参数 有就删了 在浏览器中输入c ...
- 开启unity3D的学习之路
2014年5月11号.我開始了我的Unity3D的学习之路.我将在此记录我学习过程中各个进程,这样在将来的某天,自己忘记了某部分内容时.也能够回过头来复习一下.
- x86 寻址学习
x86 寻址方式众多,什么直接寻址.间接寻址.基址寻址.基址变址寻址等等让人眼花缭乱,而 AT&T 语法对内存寻址方式做了一个很好的统一,其格式为 section:displacement(b ...