SPOJ - PHRASES Relevant Phrases of Annihilation
传送门: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 Relevant Phrases of Annihilation的更多相关文章
- SPOJ - PHRASES Relevant Phrases of Annihilation —— 后缀数组 出现于所有字符串中两次且不重叠的最长公共子串
题目链接:https://vjudge.net/problem/SPOJ-PHRASES PHRASES - Relevant Phrases of Annihilation no tags You ...
- 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 220】 PHRASES - Relevant Phrases of Annihilation
[链接]h在这里写链接 [题意] 给你n(n<=10)个字符串. 每个字符串长度最大为1e4; 问你能不能找到一个子串. 使得这个子串,在每个字符串里面都不想交出 ...
- SPOJ - PHRASES 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(后缀数组 + 二分)题解
题意: 给\(n\)个串,要你求出一个最长子串\(A\),\(A\)在每个字串至少都出现\(2\)次且不覆盖,问\(A\)最长长度是多少 思路: 后缀数组处理完之后,二分这个长度,可以\(O(n)\) ...
- 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 ...
随机推荐
- Docker-ce Centos8 笔记二:常见问题
- HP Proliant DL580 gen9 阵列卡P440AR 高速缓存 被禁用
摘录内容: IMPORTANT: This issue does NOT occur when the operating system shuts down gracefully. In addit ...
- 【Redis3.0.x】数据类型
Redis3.0.x 数据类型 五大数据类型 String(字符串) string 是 redis 最基本的类型.可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value. ...
- 天梯赛练习 L3-016 二叉搜索树的结构 (30分)
题目分析: 用数型结构先建树,一边输入一边建立,根节点的下标为1,所以左孩子为root*2,右孩子为root*2+1,输入的时候可用cin输入字符串也可用scanf不会超时,判断是否在同一层可以判断两 ...
- idea中文注释出现乱码,我靠自己解决了
如果你像我一样️,查遍google百度,半天下来还是找不到解决方案,说不定这篇博客能帮助你顺利解决呢 好了,那么开始说说我是怎么解决麻烦的. 首先,我想打开一份java文稿.光预览,它是没有任何问题的 ...
- Linux 防火墙基于 CentOS7 的防火墙操作命令
防火墙服务操作命令 重启防火墙 systemctl restart firewalld 查看防火墙状态 systemctl status firewalld 开启.关闭.重启防火墙 # 开启 serv ...
- 树莓派3B装ubuntu server后开启wifi
树莓派官网选择ubuntu server下载映像 step 1: 使用SDFormatter格式化SD卡: step2: 使用win32diskimager工具将映像写入准备好的SD卡: step3: ...
- druid discard long time none received connection问题解析
最新项目中用的druid连接数据库遇到一个困扰很久的问题 1 开始用的druid版本是1.1.22版本,由于业务需求,单个连接需要执行很久,理论上不需要用到自动回收,但为了安全,还是加了自动回收,时间 ...
- oracle ORA-00060死锁查询、表空间扩容
--查看被锁住的表 select b.owner,b.object_name,a.session_id,a.locked_mode from v$locked_object a,dba_objects ...
- 动态sql语句、逆向工程(generator)、分页助手(pagehelper)
1.动态sql语句 if if where 配合使用 <select id="selectByWhere" resultType="com.alibaba.wlq. ...