【poj1226-出现或反转后出现在每个串的最长公共子串】后缀数组
题意:求n个串的最长公共子串,子串出现在一个串中可以是它的反转串出现。总长<=10^4.
题解:

对于每个串,把反转串也连进去。
二分长度,分组,判断每个组。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std; const int N=*;
int n,sl,cl,c[N],rk[N],sa[N],Rs[N],wr[N],y[N],h[N],st[N],ed[N],fst[N],fed[N];
char s[N];
bool vis[N]; void get_sa(int m)
{
for(int i=;i<=cl;i++) rk[i]=c[i];
for(int i=;i<=m;i++) Rs[i]=;
for(int i=;i<=cl;i++) Rs[rk[i]]++;
for(int i=;i<=m;i++) Rs[i]+=Rs[i-];
for(int i=cl;i>=;i--) sa[Rs[rk[i]]--]=i; int ln=,p=;
while(p<cl)
{
int k=;
for(int i=cl-ln+;i<=cl;i++) y[++k]=i;
for(int i=;i<=cl;i++) if(sa[i]>ln) y[++k]=sa[i]-ln; for(int i=;i<=cl;i++) wr[i]=rk[y[i]];
for(int i=;i<=m;i++) Rs[i]=;
for(int i=;i<=cl;i++) Rs[wr[i]]++;
for(int i=;i<=m;i++) Rs[i]+=Rs[i-];
for(int i=cl;i>=;i--) sa[Rs[wr[i]]--]=y[i]; for(int i=;i<=cl;i++) wr[i]=rk[i];
for(int i=cl+;i<=cl+ln;i++) wr[i]=;
p=;rk[sa[]]=;
for(int i=;i<=cl;i++)
{
if(wr[sa[i]]!=wr[sa[i-]] || wr[sa[i]+ln]!=wr[sa[i-]+ln]) p++;
rk[sa[i]]=p;
}
ln*=,m=p;
}
sa[]=,rk[]=;
} void get_h()
{
int k=,j;
for(int i=;i<=cl;i++) if(rk[i]!=)
{
j=sa[rk[i]-];
if(k) k--;
while(c[i+k]==c[j+k] && i+k<=cl && j+k<=cl) k++;
h[rk[i]]=k;
}
h[]=;
} int idx(int x)
{
for(int i=;i<=n;i++)
if((st[i]<=x && x<=ed[i]) || (fst[i]<=x && x<=fed[i])) return i;
} bool check(int k)
{
memset(vis,,sizeof(vis));
for(int i=;i<=cl;i++)
{
if(h[i]<k)
{
int cnt=;
for(int j=;j<=n;j++) if(vis[j]) cnt++;
if(cnt==n) return ;
memset(vis,,sizeof(vis));
}
vis[idx(sa[i])]++;
}
int cnt=;
for(int j=;j<=n;j++) if(vis[j]) cnt++;
if(cnt==n) return ;
return ;
} int main()
{
freopen("a.in","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int num=;
cl=;
for(int i=;i<=n;i++)
{
scanf("%s",s+);
sl=strlen(s+);
if(i>) c[++cl]=++num;
st[i]=cl+;for(int j=;j<=sl;j++) c[++cl]=s[j];ed[i]=cl;
c[++cl]=++num;
fst[i]=cl+;for(int j=sl;j>=;j--) c[++cl]=s[j];fed[i]=cl;
}
if(n==) {printf("%d\n",sl);continue;}
get_sa();
get_h();
// for(int i=1;i<=cl;i++) printf("%c",c[i]);printf("\n");
// for(int i=1;i<=cl;i++) printf("%d ",c[i]);printf("\n");
// for(int i=1;i<=cl;i++) printf("%d ",sa[i]);printf("\n");
// for(int i=1;i<=cl;i++) printf("%d ",rk[i]);printf("\n");
// for(int i=1;i<=cl;i++) printf("%d ",h[i]);printf("\n");
int l=,r=cl,mid;
while(l<r)
{
mid=(l+r+)/;
if(check(mid)) l=mid;
else r=mid-;
}
printf("%d\n",l);
}
return ;
}
这一题我曾经用kmp暴力水过。。贴一下代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std; const int N=,Inf=(int)1e9;
char s[N][N],c1[N],c2[N];
int n,id,cl,l[N],nt[N],nxt[N]; void kmp_nt()
{
nt[]=;
for(int i=,p=;i<=cl;i++)
{
while(c1[p+]!=c1[i] && p) p=nt[p];
if(c1[p+]==c1[i]) p++;
nt[i]=p;
} nxt[]=;
for(int i=,p=;i<=cl;i++)
{
while(c2[p+]!=c2[i] && p) p=nxt[p];
if(c2[p+]==c2[i]) p++;
nxt[i]=p;
}
} bool kmp_td(int x)
{
for(int i=,p=;i<=l[x];i++)
{
while(c1[p+]!=s[x][i] && p) p=nt[p];
if(c1[p+]==s[x][i]) p++;
if(p==cl) return ;
}
for(int i=,p=;i<=l[x];i++)
{
while(c2[p+]!=s[x][i] && p) p=nxt[p];
if(c2[p+]==s[x][i]) p++;
// td[i]=p;
if(p==cl) return ;
}
return ;
} bool check(int len)
{
for(int i=;i+len-<=l[id];i++)
{
cl=;
for(int j=i;j<=i+len-;j++)
c1[++cl]=s[id][j],c2[len-cl+]=s[id][j];
kmp_nt();
bool bk=;
for(int j=;j<=n;j++)
if(!kmp_td(j)) {bk=;break;}
if(bk) return ;
}
} int main()
{
freopen("a.in","r",stdin);
freopen("vio.out","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int ll=,rr=Inf,mid;
for(int i=;i<=n;i++)
{
scanf("%s",s[i]+);
l[i]=strlen(s[i]+);
if(l[i]<rr) rr=l[i],id=i;
}
while(ll<rr)
{
mid=(ll+rr+)/;
if(check(mid)) ll=mid;
else rr=mid-;
}
printf("%d\n",ll);
}
return ;
}
【poj1226-出现或反转后出现在每个串的最长公共子串】后缀数组的更多相关文章
- Java算法——求出两个字符串的最长公共字符串
问题:有两个字符串str1和str2,求出两个字符串中最长公共字符串. 例如:“acbbsdef”和"abbsced"的最长公共字符串是“bbs” 算法思路: 1.把两个字符串分别 ...
- POJ1226 Substrings ——后缀数组 or 暴力+strstr()函数 最长公共子串
题目链接:https://vjudge.net/problem/POJ-1226 Substrings Time Limit: 1000MS Memory Limit: 10000K Total ...
- POJ 3294 出现在至少K个字符串中的子串
在掌握POJ 2774(两个串求最长公共子串)以及对Height数组分组后,本题还是容易想出思路的. 首先用字符集外的不同字符连接所有串,这是为了防止两个后缀在比较时超过某个字符串的分界.二分子串的长 ...
- POJ1226:Substrings(后缀数组)
Description You are given a number of case-sensitive strings of alphabetic characters, find the larg ...
- [POJ1226]Substrings(后缀数组)
传送门 给定 n 个字符串,求出现或反转后出现在每个字符串中的最长子串. 算法分析: 这题不同的地方在于要判断是否在反转后的字符串中出现.其实这并没有加大题目的难度. 只需要先将每个字符串都反过来写一 ...
- array_flip() 函数返回一个反转后的数组
定义和用法 array_flip() 函数返回一个反转后的数组,如果同一值出现了多次,则最后一个键名将作为它的值,所有其他的键名都将丢失. 如果原数组中的值的数据类型不是字符串或整数,函数将报错 ar ...
- 调用百度地图API的应用混淆后出问题
1 混淆后出问题,程序异常退出 在proguard-project.txt中添加 -libraryjars libs/BaiduLBS_Android.jar -keep class com.baid ...
- 动态规划:给出两个字符串s1和s2,返回其中最大的公共子串
求公共子字符串问题(连续的) 这个题目是当时远景能源公司现场笔试的一道题目,当时根本就不知道动态规划是什么鬼,直接上来就暴力求解,面试官很谄媚的问我,你这能求出来吗?当时很年轻的说,能啊!现在想,当时 ...
- C#中的字符串处理——找出最长数字子串
百度测试部2015年10月份的面试题之——字符串处理,找出最长的子串. 代码如下: private static string SelectNumberFromString(string input) ...
随机推荐
- js学习日记-常用正则符号参考
预定义类 量词 贪婪.惰性.支配性量词 前瞻 边界 RegExp是全局对象,RegExp.$1...$9是全局属性.当执行任意正则表达式匹配操作时,JavaScript会自动更新全局对象RegExp上 ...
- Leetcode代码补全——二叉树
在刷leetcode的过程中发现,在原网页输入答案是不需要自己构筑树和链表的,虽然便于直接思考算法,但是久而久之类似过于依赖编辑器,反而不知道如何创建树和链表,因此总结了该网页省略的部分,以其中题为例 ...
- python 基础篇 04(列表 元组 常规操作)
本节主要内容:1. 列表2. 列表的增删改查3. 列表的嵌套4. 元组和元组嵌套5. range 一. 列表1.1 列表的介绍列表是python的基础数据类型之一 ,其他编程语言也有类似的数据类型. ...
- LB
LB(LBaaS)及Load Balance as a Service是 Neutron 提供的一项高级网络服务. LBaaS 允许租户在自己的网络中创建和管理 load balancer,load ...
- 【转】cocos2dx 3.x 集成protobuf
http://www.cnblogs.com/chevin/p/6001872.html vs2013+cocos2dx 3.13.1 这篇博文是集成Lua版本的protobuf,集成C++版本的过程 ...
- hw_breakpoint使用方法
hw_breakpoint 使用方法 kprobe在 do_page_fault 函数中不能使用,那么如果真要在这里打点怎么办呢?看看hw_breakpoint是否可用: 事实证明,即便 hw_bre ...
- java基础知识(一)- 数据类型
Java有两大数据类型: 基本数据类型,基本数据类型都可以直接分配到栈中 引用数据类型,引用存放在栈中,对象本身存放在堆中 基本数据类型共有四类八种 第一类:字符型(char) 第二类:逻辑型(boo ...
- mac tomcat: error 1 operation not permitted
在用微信传一个tomcat压缩包到别人后,解压后无法用idea启动,提示 error 1 operation not permitted,但是直接用命令可以执行. 仔细查看,原来是因为mac出于安全考 ...
- 【Python】Python学习----第一模块笔记
1.python是什么? python是动态解释型的强类型定义语言. python官方版本的解释器是CPython.该解释器使用C语言开发. 当前主要使用3.x版本的python. 2.第一个pyth ...
- Java的sql语句 写关键字不需要添加单引号
Java的sql语句 写关键字不需要添加单引号