传送门:SPOJ - PHRASES(后缀数组+二分)

题意:给你n个字符串,找出一个最长的子串,他必须在每次字符串中都出现至少两次。

题解:被自己蠢哭...记录一下自己憨憨的操作,还一度质疑评测鸡(哭...

首先是多个字符串的常规操作(目前写的题少,见到的都是这样)连成一个字符串,中间用不同的且没出现过的字符隔开。然后后缀数组求出sa数组和height数组,二分子串长度,用mx数组记录该串中的这个子串的起点最大值,mi数组记录最小值,如果所有串中的mx-mi都>=k说明这个长度可以。

  1 #include<cstdio>
2 #include<algorithm>
3 #include<queue>
4 #include<iostream>
5 #include<cmath>
6 #include<cstring>
7 using namespace std;
8
9 //sa:字典序中排第i位的起始位置在str中第sa[i] sa[1~n]为有效值
10
11 //rnk:就是str第i个位置的后缀是在字典序排第几 rnk[0~n-1]为有效值
12
13 //height:字典序排i和i-1的后缀的最长公共前缀 height[2~n]为有效值,第二个到最后一个
14
15 const int INF=0x3f3f3f3f;
16 const int maxn = 1e5+10;
17 int wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn];
18 int rnk[maxn],height[maxn],be[maxn];
19 char s[maxn];
20 int r[maxn],n,len,mx[maxn],mi[maxn];
21
22 int cmp(int *r,int a,int b,int k)
23 {
24 return r[a]==r[b]&&r[a+k]==r[b+k];
25 }
26
27 void getsa(int *r,int *sa,int n,int m)//n为添加0后的总长
28 {
29 int i,j,p,*x=wa,*y=wb,*t;
30 for(i=0; i<m; i++) wsf[i]=0;
31 for(i=0; i<=n; i++) wsf[x[i]=r[i]]++;
32 for(i=1; i<m; i++) wsf[i]+=wsf[i-1];
33 for(i=n; i>=0; i--) sa[--wsf[x[i]]]=i;
34 p=1;
35 j=1;
36 for(; p<=n; j*=2,m=p){
37 for(p=0,i=n+1-j; i<=n; i++) y[p++]=i;
38 for(i=0; i<=n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
39 for(i=0; i<=n; i++) wv[i]=x[y[i]];
40 for(i=0; i<m; i++) wsf[i]=0;
41 for(i=0; i<=n; i++) wsf[wv[i]]++;
42 for(i=1; i<m; i++) wsf[i]+=wsf[i-1];
43 for(i=n; i>=0; i--) sa[--wsf[wv[i]]]=y[i];
44 swap(x,y);
45 x[sa[0]]=0;
46 for(p=1,i=1; i<=n; i++)
47 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
48 }
49 }
50
51 void getheight(int *r,int n)//n为添加0后的总长
52 {
53 int i,j,k=0;
54 for(i=1; i<=n; i++) rnk[sa[i]]=i;
55 for(i=0; i<n; i++){
56 if(k)
57 k--;
58 else
59 k=0;
60 j=sa[rnk[i]-1];
61 while(r[i+k]==r[j+k])
62 k++;
63 height[rnk[i]]=k;
64 }
65 }
66
67 bool check(int k)
68 {
69 for(int j=0;j<n;j++) mx[j]=-INF,mi[j]=INF; //一开始忘记初始化
70 for(int i=2;i<=len;i++){
71 if(height[i]>=k){
72 mx[be[sa[i]]]=max(mx[be[sa[i]]],sa[i]);
73 mi[be[sa[i]]]=min(mi[be[sa[i]]],sa[i]);
74 mx[be[sa[i-1]]]=max(mx[be[sa[i-1]]],sa[i-1]);
75 mi[be[sa[i-1]]]=min(mi[be[sa[i-1]]],sa[i-1]); //没眼睛写成了sa[i]
76 }
77 else{
78 int j=0;
79 for(j=0;j<n;j++) mx[j]=-INF,mi[j]=INF;
80 mx[be[sa[i]]]=sa[i],mi[be[sa[i]]]=sa[i];
81 }
82 int j=0;
83 for(j=0;j<n;j++){
84 if(mx[j]-mi[j]<k) break;
85 }
86 if(j==n) return true;
87 }
88 return false;
89 }
90
91 int main()
92 {
93 ios::sync_with_stdio(false);
94 cin.tie(0);
95 cout.tie(0);
96 int t;
97 cin>>t;
98 while(t--){
99 cin>>n;
100 len=0;
101 for(int i=0;i<n;i++){
102 cin>>s+len;
103 int p=strlen(s+len);
104 for(int j=0;j<p;j++){
105 r[j+len]=s[j+len]-'a'+1;
106 be[len+j]=i;
107 }
108 len+=p;
109 if(i!=n-1){
110 be[len]=i;
111 r[len++]=i+100;
112 }
113 }
114 r[len]=0;
115 getsa(r,sa,len,200);
116 getheight(r,len);
117 int l=0,r=min(len,10000);
118 int ans=0;
119 while(l<=r){
120 int mid=l+r>>1;
121 if(check(mid)){
122 ans=mid;
123 l=mid+1;
124 }
125 else r=mid-1;
126 }
127 cout<<ans<<endl;
128 }
129 return 0;
130 }

SPOJ - PHRASES

SPOJ - PHRASES Relevant Phrases of Annihilation的更多相关文章

  1. SPOJ - PHRASES Relevant Phrases of Annihilation —— 后缀数组 出现于所有字符串中两次且不重叠的最长公共子串

    题目链接:https://vjudge.net/problem/SPOJ-PHRASES PHRASES - Relevant Phrases of Annihilation no tags  You ...

  2. SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)

    [题目链接] http://www.spoj.pl/problems/PHRASES/ [题目大意] 求在每个字符串中出现至少两次的最长的子串 [题解] 注意到这么几个关键点:最长,至少两次,每个字符 ...

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

    You are the King of Byteland. Your agents have just intercepted a batch of encrypted enemy messages ...

  4. 【SPOJ 220】 PHRASES - Relevant Phrases of Annihilation

    [链接]h在这里写链接 [题意]     给你n(n<=10)个字符串.     每个字符串长度最大为1e4;     问你能不能找到一个子串.     使得这个子串,在每个字符串里面都不想交出 ...

  5. SPOJ - PHRASES Relevant Phrases of Annihilation (后缀数组)

    You are the King of Byteland. Your agents have just intercepted a batch of encrypted enemy messages ...

  6. SPOJ PHRASES Relevant Phrases of Annihilation(后缀数组 + 二分)题解

    题意: 给\(n\)个串,要你求出一个最长子串\(A\),\(A\)在每个字串至少都出现\(2\)次且不覆盖,问\(A\)最长长度是多少 思路: 后缀数组处理完之后,二分这个长度,可以\(O(n)\) ...

  7. POJ - 3294~Relevant Phrases of Annihilation SPOJ - PHRASES~Substrings POJ - 1226~POJ - 3450 ~ POJ - 3080 (后缀数组求解多个串的公共字串问题)

    多个字符串的相关问题 这类问题的一个常用做法是,先将所有的字符串连接起来, 然后求后缀数组 和 height 数组,再利用 height 数组进行求解. 这中间可能需要二分答案. POJ - 3294 ...

  8. SPOJ - PHRASES K - Relevant Phrases of Annihilation

    K - Relevant Phrases of Annihilation 题目大意:给你 n 个串,问你最长的在每个字符串中出现两次且不重叠的子串的长度. 思路:二分长度,然后将height分块,看是 ...

  9. 【SPOJ 220】Relevant Phrases of Annihilation

    http://www.spoj.com/problems/PHRASES/ 求出后缀数组然后二分. 因为有多组数据,所以倍增求后缀数组时要特判是否越界. 二分答案时的判断要注意优化! 时间复杂度\(O ...

随机推荐

  1. openstack octavia的实现与分析(二)原理,架构与基本流程

    [了解] 其实说白了,Octavia就是将用户的API请求经过逻辑处理,转换成Haproxy或者Nginx的配置参数,下发到amphora虚机中. Octavia的内部实现中,逻辑流程的处理主要使用T ...

  2. 离散傅里叶变换DFT入门

    网上对于傅里叶变换相关的文章很多(足够多),有的是从物理相关角度入场,有的从数学分析角度入场.对于有志学习相关概念的同学还是能够很好的理解的. 数学包括三大块:代数学.几何.数学分析.前两块我们在中学 ...

  3. laravel5.4 接入qq第三方登录

    第一步:先composer安装需要用到的依赖,命令行如下 composer require socialiteproviders/qq 第二步:在config/app.php 中的 providers ...

  4. 使用Python自动填写问卷星(pyppeteer反爬虫版)

    写此文的目的是为了方便寒假自己忘记填问卷星 一开始的想法和去年一样,去年就写过一版,想着今年不过就是改改数据,换换id而已,另外没想到的事情发生了... 满怀信心的写完代码 from selenium ...

  5. 详解Vue中的computed和watch

    作者:小土豆 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.cn/user/2436173500265335 1. 前言 作为一名Vue ...

  6. MySQL的CURD 增删改查

    添加 insert 语法: 单条:insert into 表名('字段1', '字段2', ...) values('值1', '值2', ...) 多条:insert into 表名('字段1', ...

  7. 【Web】HTML入门小结

    文章目录 HTML? HTML 初识元素/标签 HTML语义化标签 标题 段落 font HTMl链接 HTML图像 HTML列表 HTML div HTML 块级元素与行内元素 HTML常用带格式作 ...

  8. 汇编学习笔记——DOS及DEBUG介绍

    转自:https://www.shiyanlou.com/courses/running/332 一.课程简介 声明:该课程基于<汇编语言(第2版)>郑晓薇 编著,机械工业出版社.本节实验 ...

  9. List使用Stream流进行集合Collection的各种运算汇总:对BigDecimal求和,某个字段的和、最大值、最小值、平均值,字段去重,过滤等

    写Java接口的朋友都知道,Java 8的更新,经常会用到过滤 list<Object> 里的数据,本文就对List使用Stream流进行集合Collection的各种运算做一个汇总! 优 ...

  10. 07--Docker安装Redis

    1.拉取redis:3.2 docker pull redis:3.2 2.创建redis容器 docker run -p 6379:6379 -v /zhengcj/myredis/data:/da ...