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 ...
随机推荐
- PE556
考虑推广sum(i in Z){mu^2(i)}的做法. #include"roundCount.cpp" #include<cstdio> #include<v ...
- 注册页面的js验证
简单的用户注册页面:(html) 包含用户名格式验证.邮箱格式验证.确认密码一致性验证和必填项验证.(纯javascript) <center> <h1>用户注册</h1 ...
- POI文件导出至EXCEL,并弹出下载框
相关参考帖子 : [1]http://www.tuicool.com/articles/MnqeUr [2]http://www.oschina.net/question/253469_51638?f ...
- java的事务处理
本文转自http://zhenchengchagangzi.iteye.com/blog/1159493 java的事务处理,如果对数据库进行多次操作,每一次的执行或步骤都是一个事务.如果数据库操作在 ...
- centos vim配置高亮语法和格式化粘贴
centos vim配置高亮语法和格式化粘贴 设置vim别名和高亮grep词语 echo -e "\nalias vi=vim\nalias grep='grep --color'\n&qu ...
- 《Java多线程核心技术》读书摘要
Chapter1: 进程是操作系统管理的基本单元,线程是CPU调到的基本单元. 调用myThread.run()方法,JVM不会生成新的线程,myThread.start()方法调用两次JVM会报错. ...
- Effective C++ -----条款26:尽可能延后变量定义式的出现时间
尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率.
- ASM:《X86汇编语言-从实模式到保护模式》第8章:实模式下硬盘的访问,程序重定位和加载
第八章是一个非常重要的章节,讲述的是实模式下对硬件的访问(这一节主要讲的是硬盘),还有用户程序重定位的问题.现在整理出来刚好能和保护模式下的用户程序定位作一个对比. ★PART1:用户程序的重 ...
- SprignMVC+myBatis整合
转载自:http://lydia-fly.iteye.com/blog/2153076 学习本节内容请先看"MyBatis的基本应用".地址:http://lydia-fly.it ...
- 20145213《Java程序设计学习笔记》第六周学习总结
20145213<Java程序设计学习笔记>第六周学习总结 说在前面的话 上篇博客中娄老师指出我因为数据结构基础薄弱,才导致对第九章内容浅尝遏止地认知.在这里我还要自我批评一下,其实我事后 ...