题意:求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-出现或反转后出现在每个串的最长公共子串】后缀数组的更多相关文章

  1. Java算法——求出两个字符串的最长公共字符串

    问题:有两个字符串str1和str2,求出两个字符串中最长公共字符串. 例如:“acbbsdef”和"abbsced"的最长公共字符串是“bbs” 算法思路: 1.把两个字符串分别 ...

  2. POJ1226 Substrings ——后缀数组 or 暴力+strstr()函数 最长公共子串

    题目链接:https://vjudge.net/problem/POJ-1226 Substrings Time Limit: 1000MS   Memory Limit: 10000K Total ...

  3. POJ 3294 出现在至少K个字符串中的子串

    在掌握POJ 2774(两个串求最长公共子串)以及对Height数组分组后,本题还是容易想出思路的. 首先用字符集外的不同字符连接所有串,这是为了防止两个后缀在比较时超过某个字符串的分界.二分子串的长 ...

  4. POJ1226:Substrings(后缀数组)

    Description You are given a number of case-sensitive strings of alphabetic characters, find the larg ...

  5. [POJ1226]Substrings(后缀数组)

    传送门 给定 n 个字符串,求出现或反转后出现在每个字符串中的最长子串. 算法分析: 这题不同的地方在于要判断是否在反转后的字符串中出现.其实这并没有加大题目的难度. 只需要先将每个字符串都反过来写一 ...

  6. array_flip() 函数返回一个反转后的数组

    定义和用法 array_flip() 函数返回一个反转后的数组,如果同一值出现了多次,则最后一个键名将作为它的值,所有其他的键名都将丢失. 如果原数组中的值的数据类型不是字符串或整数,函数将报错 ar ...

  7. 调用百度地图API的应用混淆后出问题

    1 混淆后出问题,程序异常退出 在proguard-project.txt中添加 -libraryjars libs/BaiduLBS_Android.jar -keep class com.baid ...

  8. 动态规划:给出两个字符串s1和s2,返回其中最大的公共子串

    求公共子字符串问题(连续的) 这个题目是当时远景能源公司现场笔试的一道题目,当时根本就不知道动态规划是什么鬼,直接上来就暴力求解,面试官很谄媚的问我,你这能求出来吗?当时很年轻的说,能啊!现在想,当时 ...

  9. C#中的字符串处理——找出最长数字子串

    百度测试部2015年10月份的面试题之——字符串处理,找出最长的子串. 代码如下: private static string SelectNumberFromString(string input) ...

随机推荐

  1. NB-IOT的键值对

    1. 关于NB-IOT的软件开发,有一个功能,NB收到数据的时候可以唤醒处于低功耗下的MCU. 2. 2个键值对可以配置这个功能.使用键值对的方式. 3. 遇到的第一个问题,<config> ...

  2. 判断电脑CPU硬件支不支持64位

    你可以在注册表中查看: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment\PROCESSO ...

  3. oracle 认识

    有一家叫甲骨文的粮店,老板很严谨,为了防止仓库的粮食在买入卖出的时候发生问题,他制订一套流程,首先进出仓库的每一旦粮食都要求有一个编号(SCN),而且出入库之前必须先放到一个平台上(buffer ca ...

  4. 用起来超爽的Maven——入门篇

    你还在为怎样寻找.导入SSH相关依赖包纠结吗? 你还在为没有安装IDE开发工具不能编译.部署.运行项目而纠结吗? 你还在为公司项目目录结构怎样规范而纠结吗? 亲爱的纠结哥,只要你使用了Maven,一切 ...

  5. 【vim环境配置】解决ubuntu上 由YouCompleteMe插件配置不当引起的 自动补全失效的问题

    背景: 由于不可抗拒的原因,学习环境由之前centos的一台机器上,变成了ubuntu的一台机器上.因此,需要在新的ubuntu的机器上再配置一次vim环境.算起来这已经是第三次配置vim环境了(ma ...

  6. Java中的while(true)

    while(true)是一个无限循环 在内部用break或return退出循环,否则一直循环

  7. 09-Mysql数据库----外键的变种

    本节重点: 如何找出两张表之间的关系 表的三种关系 一.介绍 因为有foreign key的约束,使得两张表形成了三种了关系: 多对一 多对多 一对一 二.重点理解如果找出两张表之间的关系 分析步骤: ...

  8. LINUX系统下Java和Scala的环境配置

    最近,笔者在研究一个有关“自然语言处理”的项目,在这个项目中,需要我们用Spark进行编程.而Spark内核是由Scala语言开发的,所以在使用Spark之前,我们必须配置好Scala,而Scala又 ...

  9. SSH 项目中 使用websocket 实现网页聊天功能

    参考文章  :java使用websocket,并且获取HttpSession,源码分析    http://www.cnblogs.com/zhuxiaojie/p/6238826.html 1.在项 ...

  10. 【SSH】——封装参数不确定的分页查询

    [前言] 在BS中,分页技术的应用相当频繁.说到分页,简单的分页就很好实现了,如果在分页的基础上再加上业务逻辑,这就使得分页的技术更加的灵活了. [简单分页] 我们先看一种简单的分页,为了做到复用,我 ...