SPOJ220 Relevant Phrases of Annihilation(后缀数组)
引用罗穗骞论文中的话:
先将n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组。然后二分答案,再将后缀分组。判断的时候,要看是否有一组后缀在每个原来的字符串中至少出现两次,并且在每个原来的字符串中,后缀的起始位置的最大值与最小值之差是否不小于当前答案(判断能否做到不重叠,如果题目中没有不重叠的要求,那么不用做此判断)。这个做法的时间复杂度为O(nlogn)。
二分枚举长度,对每个长度遍历height[]数组,将height[]数组分块,每个块内任意两串的lcp均大于等于m,则这些串的前m位相同。
使用mi[], mx数组存储每个串匹配成功时下标最大与最小值,当mx[tp] - mi[tp] >= m 时说明找到两个串且不重叠。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int N = 1100000; int sa[N], rank[N], height[N]; int mi[15], mx[15]; char tp[100008];
int str[N];
int vis[15];
int hs[N]; int wa[N],wb[N],wv[N],ws1[N];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws1[i]=0;
for(i=0;i<n;i++) ws1[x[i]=r[i]]++;
for(i=1;i<m;i++) ws1[i]+=ws1[i-1];
for(i=n-1;i>=0;i--) sa[--ws1[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) ws1[i]=0;
for(i=0;i<n;i++) ws1[wv[i]]++;
for(i=1;i<m;i++) ws1[i]+=ws1[i-1];
for(i=n-1;i>=0;i--) sa[--ws1[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
} bool check(int n, int m, int num){
memset(vis, 0, sizeof(vis));
memset(mi, 0x3F, sizeof(mi));
memset(mx, 0, sizeof(mx));
int cnt = 0;
for(int i = 1; i <= n; i++){
if(height[i] >= m){
int tp = hs[sa[i]];
mi[tp] = min(mi[tp], sa[i]);
mx[tp] = max(mx[tp], sa[i]);
if(mx[tp] - mi[tp] >= m){
if(!vis[tp]){
cnt++;
vis[tp] = 1;
}
} tp = hs[sa[i - 1]];
mi[tp] = min(mi[tp], sa[i - 1]);
mx[tp] = max(mx[tp], sa[i - 1]);
if(mx[tp] - mi[tp] >= m){
if(!vis[tp]){
cnt++;
vis[tp] = 1;
}
}
}else{
if(cnt == num){
return true;
}
memset(vis, 0, sizeof(vis));
memset(mi, 0x3F, sizeof(mi));
memset(mx, 0, sizeof(mx));
cnt = 0;
}
}
return false;
} int main(){
int t;
cin>>t;
while(t--){
int n = 0;
int mini = 100000000;
scanf("%d", &n);
int len = 0;
for(int t = 0 ; t < n; t++){
scanf("%s", tp);
int m = strlen(tp);
mini = min(mini, m);
for(int i = len , j = 0; j < m; i++, j++){
str[i] = tp[j];
hs[i] = t;
}
len += m + 1;
if(t != n - 1){
str[len - 1] = t + 130;
}
}
len--;
str[len] = 0;
da(str, sa, len + 1, 256);
calheight(str, sa, len);
int ans = 0;
int l =1, r = mini/ 2;
while(l <= r){
int m = (l + r)>>1;
if(check(len, m, n)){
l = m + 1;
ans = m;
}else{
r = m - 1;
}
}
printf("%d\n", ans); }
return 0;
}
SPOJ220 Relevant Phrases of Annihilation(后缀数组)的更多相关文章
- SPOJ - PHRASES Relevant Phrases of Annihilation —— 后缀数组 出现于所有字符串中两次且不重叠的最长公共子串
题目链接:https://vjudge.net/problem/SPOJ-PHRASES PHRASES - Relevant Phrases of Annihilation no tags You ...
- 2018.11.30 spoj220 Relevant Phrases of Annihilation(后缀数组+二分答案)
传送门 代码: 先用特殊字符把所有字符串连接在一起. 然后二分答案将sasasa数组分组. 讨论是否存在一个组满足组内对于每一个字符串都存在两段不相交字串满足条件. #include<bits/ ...
- SPOJ220 Relevant Phrases of Annihilation
http://www.spoj.com/problems/PHRASES/ 题意:给n个串,求n个串里面都有2个不重叠的最长的字串长度. 思路:二分答案,然后就可以嘿嘿嘿 PS:辣鸡题目毁我青春,一开 ...
- POJ - 3294~Relevant Phrases of Annihilation SPOJ - PHRASES~Substrings POJ - 1226~POJ - 3450 ~ POJ - 3080 (后缀数组求解多个串的公共字串问题)
多个字符串的相关问题 这类问题的一个常用做法是,先将所有的字符串连接起来, 然后求后缀数组 和 height 数组,再利用 height 数组进行求解. 这中间可能需要二分答案. POJ - 3294 ...
- SPOJ - PHRASES K - Relevant Phrases of Annihilation
K - Relevant Phrases of Annihilation 题目大意:给你 n 个串,问你最长的在每个字符串中出现两次且不重叠的子串的长度. 思路:二分长度,然后将height分块,看是 ...
- 【SPOJ 220】Relevant Phrases of Annihilation
http://www.spoj.com/problems/PHRASES/ 求出后缀数组然后二分. 因为有多组数据,所以倍增求后缀数组时要特判是否越界. 二分答案时的判断要注意优化! 时间复杂度\(O ...
- SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)
[题目链接] http://www.spoj.pl/problems/PHRASES/ [题目大意] 求在每个字符串中出现至少两次的最长的子串 [题解] 注意到这么几个关键点:最长,至少两次,每个字符 ...
- SPOJ 220 Relevant Phrases of Annihilation(后缀数组)
You are the King of Byteland. Your agents have just intercepted a batch of encrypted enemy messages ...
- SPOJ - PHRASES Relevant Phrases of Annihilation (后缀数组)
You are the King of Byteland. Your agents have just intercepted a batch of encrypted enemy messages ...
随机推荐
- RPC(Remote Procedure Call Protocol)——远程过程调用协议 学习总结
首先了解什么叫RPC,为什么要RPC,RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需 ...
- Java web中为什么要用Service接口和DAO接口?
面向接口:依赖倒转原理----使用service接口的原因是为了让表示层不依赖于业务层的具体实现,使用dao接口的原理也是如此,而且便于spring ioc容器,当修改dao层,时不需要修改servi ...
- Extjs 组件共用(单例)问题
说明: 将store初始化在类定义时便创建, store实例将成为该类的单例 代码: 测试: 说明: 将store初始化放入initComponent函数中. 每次都将创建一个新的实例. 代码: 测 ...
- Objective C 快速入门学习二
Objective-C 类.对象.方法 1.编写一个复数类: #import <Foundation/Foundation.h>@interface Complex: NSObject / ...
- PHP 常量
1.__NAMESPACE__ http://php.net/manual/zh/language.namespaces.nsconstants.php
- 【leetcode】Valid Number
Valid Number Validate if a given string is numeric. Some examples:"0" => true" 0.1 ...
- perl Can't use string Cxxx) as a symbol ref while "strict refs" in use at XXXX.pl错误
今天写脚本遇到Can't use string ("bond2 Link encap:InfiniBand ") as a symbol ref while "s ...
- 阿里2014校招笔试题(南大)——利用thread和sleep生成字符串的伪随机序列
引言:题目具体描述记不大清了,大概是:Linux平台,利用线程调度的随机性和sleep的不准确性,生成一个各位均不相同的字符数组的伪随机序列.不得使用任何库函数.(这句记得清楚,当时在想线程库算不算, ...
- Java for LintCode 链表插入排序
用插入排序对链表排序 解题思路: 最省时间的方法是使用优先级队列,但是无法通过,那就直接插入排序好了. public ListNode insertionSortList(ListNode head) ...
- 自定义View和ViewGroup
为了扫除学习中的盲点,尽可能多的覆盖Android知识的边边角角,决定对自定义View做一个稍微全面一点的使用方法总结,在内容上面并没有什么独特的地方,其他大神们的博客上面基本上都有讲这方面的内容,如 ...