【UVA11107 训练指南】Life Forms【后缀数组】

题意

输入n(n<=100)个字符串,每个字符串长度<=1000,你的任务是找出一个最长的字符串使得超过一半的字符串都包含这个字符串。

分析

训练指南上后缀数组的一道例题,据说很经典(估计也就是height分组比较常用)。但是训练指南上给出的中文题面真滴坑B啊!书上说,连续出现,我懵逼了好久!

我们把这n个字符串连成一个长的字符串S,且中间用不同的未出现的字符相隔开(为什么隔开我们后面说),比如样例一会变为abcdefg1bcdefgh2cdefghi3。这样每一段是一个原字符串。然后问题转换为,在S字符串中,找出一个最长的字符串,使得至少有n/2的匹配点与这个最长的字符串相匹配,且匹配点分别位于至少n/2段。

求最长的时候我们二分答案,然后判断mid是否满足条件。关键是如何判断。我们回想一下通过height数组求LCP的方法,我们知道LCP(i,j)=RMQ(height,rank[i]+1,rank[j]).这里和这个原理是类似的。我们遍历height数组,当height[i]<mid的时候,就新增一个分组。也就是每个分组内的LCP都是>=mid的。然后判断一下这个分组内的后缀是否符合上面说的那个条件(既分组内至少有n/2个后缀,且后缀分别位于至少n/2段)。如果符合则说明mid是合法的。我们上面说过,不同的原串我们在合成S的时候,之间是用特殊字符隔开的,就是为了保证这里每个LCP都是在一个段内。

当时我还在纠结过,这样只是求出最长长度,但是题目要求输出啊。其实,你只要再跑一下上面判断的过程,把那些符合条件的LCP都输出出来就可以了。

mmp宿舍又又又半夜停电还特么这么多蚊子,感觉最后被劝退ACM的不是自己的菜而是暑假集训期间宿舍的温度····

下面是ac的code

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5
  6 using namespace std;
  7 const int maxn=100+10;
  8 const int maxs=1000+100;
  9 char s[maxn*maxs];
 10 int c[maxn*maxs],t[maxn*maxs],t2[maxn*maxs],sa[maxn*maxs];
 11 int n,N;
 12 void build_sa(int m){
 13     int *x=t,*y=t2;
 14     for(int i=0;i<m;i++)c[i]=0;
 15     for(int i=0;i<n;i++)c[x[i]=s[i]]++;
 16     for(int i=1;i<m;i++)c[i]+=c[i-1];
 17     for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
 18
 19     for(int k=1;k<=n;k<<=1){
 20         int p=0;
 21         for(int i=n-k;i<n;i++)y[p++]=i;
 22         for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
 23         for(int i=0;i<m;i++)c[i]=0;
 24         for(int i=0;i<n;i++)c[x[y[i]]]++;//这里为啥是这样?一会结合基数排序想一下
 25         for(int i=1;i<m;i++)c[i]+=c[i-1];
 26         for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
 27         swap(x,y);
 28         p=1,x[sa[0]]=0;
 29         for(int i=1;i<n;i++)
 30           x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
 31         if(p>=n)break;
 32         m=p;
 33     }
 34 }
 35
 36 int Rank[maxn*maxs],height[maxn*maxs];
 37 void getHeight(){//这里有个bug,sa[0]不能等于0
 38     int k=0;
 39     for(int i=0;i<n;i++)Rank[sa[i]]=i;
 40     for(int i=0;i<n;i++){
 41         if(i==0&&Rank[i]==0)
 42          continue;
 43         if(k)k--;
 44         int j=sa[Rank[i]-1];
 45         while(s[i+k]==s[j+k])k++;
 46         height[Rank[i]]=k;
 47     }
 48 }
 49
 50 char word[maxs];
 51 int idx[maxn*maxs];
 52 int maxlen;
 53 void add(int len,int id){
 54     for(int i=0;i<len;i++){
 55         idx[n]=id;
 56         s[n++]=word[i]-‘a‘;
 57     }
 58     s[n]=26+id;
 59     idx[n++]=N;
 60 }
 61
 62 bool good(int L,int R){
 63     if(R-L+1<=N/2)
 64         return false;
 65     int res=0;
 66     int vis[maxn];
 67     memset(vis,0,sizeof(vis));
 68     for(int i=L;i<=R;i++){
 69         int id=idx[sa[i]];
 70         if(!vis[id]&&id!=N){
 71             vis[id]=1;
 72             res++;
 73         }
 74     }
 75     if(res>N/2)
 76         return true;
 77     return false;
 78 }
 79
 80 bool judge(int mid){
 81     int L=0;
 82     for(int R=0;R<n;R++){
 83         if(height[R]<mid){
 84             if(good(L,R-1)){
 85                 return true;
 86             }
 87             L=R;
 88         }
 89     }
 90     return false;
 91 }
 92
 93
 94 void print(int mid){
 95     int L=0;
 96     for(int R=0;R<n;R++){
 97         if(height[R]<mid){
 98             if(good(L,R-1)){
 99                 for(int i=0;i<mid;i++){
100                     printf("%c",s[i+sa[L]]+‘a‘);
101                 }
102                 printf("\n");
103             }
104         L=R;
105         }
106     }
107 }
108 int main(){
109     int kase=0;
110     while(scanf("%d",&N)!=EOF&&N){
111         if(kase)printf("\n");
112         kase=1;
113         n=0;
114         for(int i=0;i<N;i++){
115             scanf("%s",word);
116             int len=strlen(word);
117             maxlen=max(maxlen,len);
118             add(len,i);
119         }
120         if(N==1){
121             printf("%s\n",word);
122             continue;
123         }
124         build_sa(26+N);
125         getHeight();
126         int L=1,R=maxlen;
127         int ans=-1;
128         while(L<=R){
129             int M=L+(R-L)/2;
130             if(judge(M))
131             {
132                 ans = M;
133                 L=M+1;
134             }
135             else
136                 R=M-1;
137         }
138         if(ans==-1){
139             printf("?\n");
140             continue;
141         }
142         print(ans);
143     }
144 return 0;
145 }

原文地址:https://www.cnblogs.com/LQLlulu/p/9440481.html

时间: 2024-12-07 22:21:03

【UVA11107 训练指南】Life Forms【后缀数组】的相关文章

POJ 3294 Life Forms (后缀数组)

题目大意: 求出在m个串中出现过大于m/2次的子串. 思路分析: 如果你只是直接跑一次后缀数组,然后二分答案扫描的话. 那么就试一下下面这个数据. 2 abcdabcdefgh efgh 这个数据应该输出 efgh 问题就在于对于每一个串,都只能参与一次计数,所以在check的时候加一个标记数组是正解. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring>

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

POJ3294:Life Forms(后缀数组)

Description You may have wondered why most extraterrestrial life forms resemble humans, differing by superficial traits such as height, colour, wrinkles, ears, eyebrows and the like. A few bear no human resemblance; these typically have geometric or

Poj 3294 Life Forms (后缀数组 + 二分 + Hash)

题目链接: Poj 3294 Life Forms 题目描述: 有n个文本串,问在一半以上的文本串出现过的最长连续子串? 解题思路: 可以把文本串用没有出现过的不同字符连起来,然后求新文本串的height.然后二分答案串的长度K,根据K把新文本串的后缀串分块,统计每块中的原文本串出现的次数,大于原文本串数目的一半就作为答案记录下来,对于输出字典序,height就是排好序的后缀数组,只要按照顺序输出即可. 1 #include <cstdio> 2 #include <cstring>

2016多校联合训练4 F - Substring 后缀数组

Description ?? is practicing his program skill, and now he is given a string, he has to calculate the total number of its distinct substrings. But ?? thinks that is too easy, he wants to make this problem more interesting. ?? likes a character X very

POJ 3294 UVA 11107 Life Forms 后缀数组

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

poj3294 UVA 11107 Life Forms 后缀数组

http://poj.org/problem?id=3294 Life Forms Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 9931   Accepted: 2739 Description You may have wondered why most extraterrestrial life forms resemble humans, differing by superficial traits such

POJ3294--Life Forms 后缀数组+二分答案 大于k个字符串的最长公共子串

Life Forms Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 10800   Accepted: 2967 Description You may have wondered why most extraterrestrial life forms resemble humans, differing by superficial traits such as height, colour, wrinkles, e

POJ3294---Life Forms(后缀数组,二分+给后缀分组)

Description You may have wondered why most extraterrestrial life forms resemble humans, differing by superficial traits such as height, colour, wrinkles, ears, eyebrows and the like. A few bear no human resemblance; these typically have geometric or