【SPOJ220】Relevant Phrases of Annihilation(后缀数组,二分)

题意:

n<=10,len<=1e4

思路:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<iostream>
  6 #include<algorithm>
  7 #include<map>
  8 #include<set>
  9 #include<queue>
 10 #include<vector>
 11 using namespace std;
 12 typedef long long ll;
 13 typedef unsigned int uint;
 14 typedef unsigned long long ull;
 15 typedef pair<int,int> PII;
 16 typedef vector<int> VI;
 17 #define fi first
 18 #define se second
 19 #define MP make_pair
 20 #define N   210000
 21 #define MOD 1000000007
 22 #define eps 1e-8
 23 #define pi acos(-1)
 24 #define oo  1000000000
 25
 26 char ch[N];
 27
 28 int n,i,s[N],sa[N],wa[N],wb[N],wc[N],wd[N],height[N],rank[N],
 29     a[N],b[N],c[N],d[N],num[N],M;
 30
 31 int read()
 32 {
 33    int v=0,f=1;
 34    char c=getchar();
 35    while(c<48||57<c) {if(c==‘-‘) f=-1; c=getchar();}
 36    while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
 37    return v*f;
 38 }
 39
 40 bool cmp(int *r,int a,int b,int l)
 41 {
 42     return r[a]==r[b]&&r[a+l]==r[b+l];
 43 }
 44
 45 void getsa(int *r,int *sa,int n,int m)
 46 {
 47     int *x=wa,*y=wb,j,p;
 48     for(i=0;i<n;i++) wc[x[i]=r[i]]++;
 49     for(i=1;i<m;i++) wc[i]+=wc[i-1];
 50     for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;
 51     for(j=1,p=1;p<n;j*=2,m=p)
 52     {
 53         p=0;
 54         for(i=n-j;i<n;i++) y[p++]=i;
 55         for(i=0;i<n;i++)
 56          if(sa[i]>=j) y[p++]=sa[i]-j;
 57         for(i=0;i<n;i++) wd[i]=x[y[i]];
 58         for(i=0;i<m;i++) wc[i]=0;
 59         for(i=0;i<n;i++) wc[wd[i]]++;
 60         for(i=1;i<m;i++) wc[i]+=wc[i-1];
 61         for(i=n-1;i>=0;i--) sa[--wc[wd[i]]]=y[i];
 62         swap(x,y);
 63         p=1; x[sa[0]]=0;
 64         for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
 65     }
 66 }
 67
 68 void getheight(int *r,int *sa,int n)
 69 {
 70     int i,j,k=0;
 71     for(i=1;i<=n;i++) rank[sa[i]]=i;
 72     for(i=0;i<n;height[rank[i++]]=k)
 73     {
 74         if(k) k--;
 75         j=sa[rank[i]-1];
 76         while(r[i+k]==r[j+k]) k++;
 77     }
 78 }
 79
 80 void init()
 81 {
 82         memset(s,0,sizeof(s));
 83         memset(sa,0,sizeof(sa));
 84         memset(wa,0,sizeof(wa));
 85         memset(wb,0,sizeof(wb));
 86         memset(wc,0,sizeof(wc));
 87         memset(wd,0,sizeof(wd));
 88         memset(height,0,sizeof(height));
 89         memset(rank,0,sizeof(rank));
 90 }
 91
 92 bool isok(int K)
 93 {
 94     int i=1;
 95     while(i<n)
 96     {
 97         i++;
 98         if(height[i]>=K)
 99         {
100             int st=i;
101             while(i<=n&&height[i]>=K) i++;
102             if(st<=i-1)
103             {
104                 int ed=i-1;
105                 for(int j=1;j<=M;j++)
106                 {
107                     b[j]=0;
108                     c[j]=oo;
109                     d[j]=-oo;
110                 }
111                 for(int j=st-1;j<=ed;j++)
112                 {
113                     int t=num[sa[j]];
114                     b[t]++;
115                     c[t]=min(c[t],sa[j]);
116                     d[t]=max(d[t],sa[j]);
117                 }
118                 int flag=1;
119                 for(int j=1;j<=M;j++)
120                 {
121                       if(b[j]<2){flag=0; break;}
122                       if(d[j]-c[j]<K){flag=0; break;}
123                 }
124                 if(flag) return 1;
125             }
126         }
127     }
128     return 0;
129 }
130
131 int main()
132 {
133     freopen("spoj220.in","r",stdin);
134     freopen("spoj220.out","w",stdout);
135     int cas;
136     scanf("%d",&cas);
137     while(cas--)
138     {
139         init();
140         scanf("%d",&M);
141         n=-1;
142         for(int i=1;i<=M;i++)
143         {
144             scanf("%s",ch);
145             int t=strlen(ch);
146             for(int j=0;j<t;j++)
147             {
148                 s[++n]=ch[j]-‘a‘+20;
149                 num[n]=i;
150             }
151             s[++n]=i;
152             num[n]=0;
153         }
154         getsa(s,sa,n+1,100);
155         getheight(s,sa,n);
156     //    printf("1\n");
157         int L=1;
158         int R=10000;
159         int last=0;
160         while(L<=R)
161         {
162             int mid=(L+R)>>1;
163             if(isok(mid)){last=mid; L=mid+1;}
164              else R=mid-1;
165         }
166         printf("%d\n",last);
167     }
168     return 0;
169 }
170      

原文地址:https://www.cnblogs.com/myx12345/p/9648810.html

时间: 2024-08-03 09:28:19

【SPOJ220】Relevant Phrases of Annihilation(后缀数组,二分)的相关文章

SPOJ220 Relevant Phrases of Annihilation(后缀数组)

引用罗穗骞论文中的话: 先将n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组.然后二分答案,再将后缀分组.判断的时候,要看是否有一组后缀在每个原来的字符串中至少出现两次,并且在每个原来的字符串中,后缀的起始位置的最大值与最小值之差是否不小于当前答案(判断能否做到不重叠,如果题目中没有不重叠的要求,那么不用做此判断).这个做法的时间复杂度为O(nlogn). 二分枚举长度,对每个长度遍历height[]数组,将height[]数组分块,每个块内任意两串的lcp均大于等于

SPOJ 220. Relevant Phrases of Annihilation(后缀数组多次不重叠子串)

题目大意:给定N个串,求每个串至少出现两次的最长子串. 解题思路:每个字符串至少出现两次且不可重叠的最长子串:二分枚举长度后在同一分组中对每一个字符串保留一个最小的位置和一个最大的位置,最后查看是否每个串在同一组中都有至少两个后缀,并且后缀的坐标差大于枚举的长度. POJ Problem Set (classical) 220. Relevant Phrases of Annihilation Problem code: PHRASES You are the King of Byteland.

SPOJ220 Relevant Phrases of Annihilation

http://www.spoj.com/problems/PHRASES/ 题意:给n个串,求n个串里面都有2个不重叠的最长的字串长度. 思路:二分答案,然后就可以嘿嘿嘿 PS:辣鸡题目毁我青春,一开始二分的时候ans没有赋初值为0,结果没答案的时候就会输出奇怪的数字T_T,其实主要还是怪我不小心.. 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5

SPOJ 220 Relevant Phrases of Annihilation (后缀数组)

题目大意: 求在m个串中同时出现两次以上且不覆盖的子串的长度. 思路分析: 二分答案,然后check是否满足,判断不覆盖的方法就是用up down 来处理边界. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <map> #include <string> #define maxn 110005 using n

hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分)

Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 288    Accepted Submission(s): 108 Problem Description Long long ago, there lived a lot of rabbits in the forest. One day, the

BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )

二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) --------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cctype> using namespace std; typedef long long

hdu 5008(2014 ACM/ICPC Asia Regional Xi&#39;an Online ) Boring String Problem(后缀数组&amp;二分)

Boring String Problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 219    Accepted Submission(s): 45 Problem Description In this problem, you are given a string s and q queries. For each que

【bzoj4310】跳蚤 后缀数组+二分

题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个,并在选出来的 k 个子串中选择字典序最大的那一个.他称其为“魔力串”. 现在他想找一个最优的分法让“魔力串”字典序最小. 输入 第一行一个整数 k. 接下来一个长度不超过 105 的字符串 S. 输出 输出一行,表示字典序最小的“魔力串”. 样例输入 13 bcbcbacbbbbbabbacbcb

WHU---1084 - 连续技 (后缀数组+二分)

Description 不管是什么武功,多少都会有一或两个连续技多次出现,这些连续技常常是发明该武功的人的习惯性动作,如果这些动作被对手分析出来了,就很容易被对手把握住先机.比如松风剑谱里面有一式叫做迎风傲骨是如下的动作: 劈 刺 削 刺 削 踢 刺 削 刺 削 很明显 刺-削 这个连续动作出现了4次,而 刺-削-刺-削 这个连续动作则出现了两次. 现在刘白宇弄到了一本魔教的掌法,想让你帮忙来分析其中最长的且出现尽量多的连续技,当然,他不好意思麻烦你太久,只想让你告诉它这个连续技有多长并且出现了

poj 3261 Milk Patterns 后缀数组+二分

1 /*********************************************************** 2 题目: Milk Patterns(poj 3261) 3 链接: http://poj.org/problem?id=3261 4 题意: 给一串数字,求这些数字中公共子串个数大于k的 5 最长串. 6 算法: 后缀数组+二分 7 ***********************************************************/ 8 #incl