【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) ...
随机推荐
- mac 下 安装php扩展 - mcrypt
由于自带的libmcrypt 可能版本低 另外通过brew安装的也不管用得去下载libmcrypt后编译安装 tar zxvf libmcrypt-2.5.8.tar.gz cd libmcrypt- ...
- python基础——重访类型分类
python基础--重访类型分类 对象根据分类来共享操作:例如,字符串.列表和元组都共享诸如合并.长度和索引等序列操作. 只有可变对象(列表.字典和集合)可以原处修改:我们不能原处修改数字,字符串.元 ...
- Clean Code 《代码整洁之道》前四章读书笔记
第一章: 整洁的代码只做好一件事 减少重复代码 提高表达力 提早构建简单抽象 让营地比你来时更干净 第二章:有意义的命名 名副其实:如果名称需要注释来补充,就不算是名副其实. ...
- Loadrunner11.0安装与简单使用
公司开发了APP或者微信小程序啊什么的,都会先进行性能测试,而性能测试一般肯定会来测试接口的压测,并发.Loadrunner是一个很强大的测试工具,它是一种预测系统行为和性能的负载测试工具.通过以模拟 ...
- Struts2(四.注册时检查用户名是否存在及Action获取数据的三种方式)
一.功能 1.用户注册页面 <%@ page language="java" contentType="text/html; charset=UTF-8" ...
- MySQL linux错误处理
https://cloud.tencent.com/developer/article/1023732 mysql5.7 ERROR 1045 (28000): Access denied for u ...
- DM8168通过GPMC接口与FPGA高速数据通信实现
硬件:TI达芬奇TMS320DM8168(以下简称DSP).EP4CE6E22C8N(以下简称FPGA) 软件:linux-2.6.37 转载请注明出处- http://www.cnblogs.com ...
- IDE API SDK JDK
一.IDE 英文全称:Integrated Development Environment 中文名称:集成开发环境 本质:应用程序 功能:提供程序开发环境 组成:代码编辑器.编译器.调试器.图形用户界 ...
- Daily Scrum02 12.01
今天是2013年12月的第一天,希望大家都有一个新的开始,一起努力! Member Today's Task Tomorrow's Task 李孟 Task 856: 熟悉单元测试方法熟悉单元 ...
- 软工实践 - 第二十八次作业 Beta 冲刺(6/7)
队名:起床一起肝活队 组长博客:https://www.cnblogs.com/dawnduck/p/10146478.html 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过 ...