后缀数组LCP + 二分 - UVa 11107 Life Forms

Life Forms

Problem‘s Link



Mean:

给你n个串,让你找出出现次数大于n/2的最长公共子串。如果有多个,按字典序排列输出。

analyse:

经典题。

直接二分判断答案。

判断答案p时,我们扫一遍height数组,如果height[i]<p时开辟一个新段。

判断时用set存储所在串编号,不仅起到去重的作用,而且也起到统计段长的作用。

Time complexity: O(N*logN)

Source code: 

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-09-02-15.01
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long(LL);
typedef unsigned long long(ULL);
const double eps(1e-8);

const int MAXN=10001010;
char s[MAXN],ss[1010];

//以下为倍增算法求后缀数组
int wa[MAXN*2],wb[MAXN*2],wv[MAXN],Ws[MAXN];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
/**< 传入参数:str,sa,len+1,ASCII_MAX+1 */
void da(const char *r,int *sa,int n,int m)
{
     int i,j,p,*x=wa,*y=wb,*t;
     for(i=0; i<m; i++) Ws[i]=0;
     for(i=0; i<n; i++) Ws[x[i]=r[i]]++;
     for(i=1; i<m; i++) Ws[i]+=Ws[i-1];
     for(i=n-1; i>=0; i--) sa[--Ws[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++) Ws[i]=0;
           for(i=0; i<n; i++) Ws[wv[i]]++;
           for(i=1; i<m; i++) Ws[i]+=Ws[i-1];
           for(i=n-1; i>=0; i--) sa[--Ws[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;
}
int sa[MAXN],Rank[MAXN],height[MAXN];
//求height数组
/**< str,sa,len */
void calheight(const char *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++);
     // Unified
     for(int i=n; i>=1; --i) ++sa[i],Rank[i]=Rank[i-1];
}

vector<pair<int,int> > same;
int found(int x)
{
     int si=same.size();
     for(int i=0;i<si;++i)
     {
           if(x>=same[i].first && x<=same[i].second)
                 return same[i].first;
     }
}

int len,n;
bool judge(int p,bool ty)
{
     bool f=false;
     set<int> sta;
     sta.insert(found(sa[1]-1));
     for(int i=2;i<=len;++i)
     {
           while(i<=len && height[i]>=p)
                 sta.insert(found(sa[i++]-1));
           if(sta.size()*2>n)
           {
                 if(ty) return true;
                 else
                 {
                       for(int j=0;j<p;++j)
                             printf("%c",s[sa[i-1]-1+j]+‘a‘);
                       puts("");
                 }
           }
           sta.clear();
           sta.insert(found(sa[i]-1));
     }
     return f;
}

int main()
{
     int Cas=0;
     while(scanf("%d",&n),n)
     {
           same.clear();
           int st,en,maxLen=1;
           memset(s,0,sizeof s);
           for(int i=0;i<n;++i)
           {
                 scanf("%s",ss);
                 maxLen=max(maxLen,(int)strlen(ss));
                 st=strlen(s);
                 strcat(s,ss);
                 ss[0]=‘z‘+1+i,ss[1]=‘\0‘;
                 strcat(s,ss);
                 en=strlen(s);
                 same.push_back(make_pair(st,en-1));
           }
           len=strlen(s);
           if(Cas++) puts("");
           if(n==1)
           {
                 s[len-1]=‘\0‘;
                 continue;
           }
           for(int i=0;i<len;++i) s[i]-=‘a‘;
           da(s,sa,len+1,130);
           calheight(s,sa,len);
           if(!judge(1,1))
           {
                 puts("?");
                 continue;
           }
           int l=1,r=maxLen+1,mid;
           while(r>l+1)
           {
                 int mid = l+(r-l)/2;
                 if(judge(mid,1)) l = mid;
                 else r = mid;
           }
           judge(l,0);
     }
     return 0;
}
/*

*/

时间: 2024-10-22 14:31:45

后缀数组LCP + 二分 - UVa 11107 Life Forms的相关文章

poj 1743 最长不重叠重复子串 后缀数组+lcp+二分

题比较容易读懂,但是建模需动点脑子: 一个子串加常数形成的子串认为跟子串相同,求最长不重叠重复子串 题目中说 is disjoint from (i.e., non-overlapping with) at least one of its other appearance(s) 意味着不能重叠,举个例子 1, 2,3,  52, 53,54 1,2, 3和 52, 53,54满足题意,差值为51 枚举差值肯定不行------看了题解明白的:: 后项减去前一项得到: 1,1,1,49,1,1  

uva 11107 - Life Forms(后缀数组)

题目链接:uva 11107 - Life Forms 题目大意:给定n个字符串,求一个最长的字符串,为n/2个字符串的子串. 解题思路:后缀数组,处理除后缀数组后,二分长度,每次遍历height数组,当长度不足时就分段,如果存在一段中包含n/2个起点,则为可行长度. #include <cstdio> #include <cstring> #include <set> #include <algorithm> using namespace std; co

UVA 11107 - Life Forms(Hash+LCP)

UVA 11107 - Life Forms 题目链接 题意:给定一个字符串,找出重复出现超过m次的字串的最大开始下标 思路:hash大法,需要点人品,然后二分答案,每次利用hash值去找出最大下标即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef unsigned long long ull; const ull x = 123; c

BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 1890  Solved: 877 [Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

poj 2774 Long Long Message 后缀数组LCP理解

题目链接 题意:给两个长度不超过1e5的字符串,问两个字符串的连续公共子串最大长度为多少? 思路:两个字符串连接之后直接后缀数组+LCP,在height中找出max同时满足一左一右即可: #include<iostream> #include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<map> #include<queue&

hdu 4691 最长公共前缀 后缀数组 +lcp+rmq

http://acm.hdu.edu.cn/showproblem.php?pid=4691 去年暑假多校赛的题,当时还不会后缀数组 现在会了,其实自己组合后缀数组跟rmq还是对的,但是题意理解有问题,于是折腾了很久,,,, 此处简单解释下题目样例吧,希望对读者有帮助  以最后一组数据为例 myxophytamyxopodnabnabbednabbingnabit 6 0 9 9 16 16 19 19 25 25 32 32 37 前两行不解释,题目叙述很清楚 从第三行,0 9 指的是第一个字

POJ 3294 UVA 11107 Life Forms 后缀数组

相同的题目,输出格式有区别. 给定n个字符串,求最长的子串,使得它同时出现在一半以上的串中. 不熟悉后缀数组的童鞋建议先去看一看如何用后缀数组计算两个字符串的最长公共子串 Ural1517 这道题的思路也是基本相同的,都是利用了后缀数组的良好性质. #include <iostream> #include <cstring> #include <cstdio> using namespace std; const int MAX = 100500; const int

hdu 3518 Boring counting 后缀数组LCP

题目链接 题意:给定长度为n(n <= 1000)的只含小写字母的字符串,问字符串子串不重叠出现最少两次的不同子串个数; input: aaaa ababcabb aaaaaa # output 2 3 3 思路:套用后缀数组求解出sa数组和height数组,之后枚举后缀的公共前缀长度i,由于不能重叠,所以计数的是相邻height不满足LCP >= i的. 写写对后缀数组倍增算法的理解: 1.如果要sa数组对应的值也是1~n就需要在最后加上一个最小的且不出现的字符'#',里面y[]是利用sa数

【BZOJ1717&amp;POJ3261】Milk Patterns(后缀数组,二分)

题意:求字符串的可重叠的k次最长重复子串 n<=20000 a[i]<=1000000 思路:后缀数组+二分答案x,根据height分组,每组之间的height>=x 因为可以重叠,所以只要判断是否有一组的height个数>=k即可 1 var sa,rank,x,y,a,wc,wd,height:array[0..1100000]of longint; 2 n,m,i,l,r,mid,last,k1:longint; 3 4 procedure swap(var x,y:long