hdu2328(后缀数组 + 二分)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2328
题意: 求 n 个串的字典序最小的最长公共子串
思路: 本题中单个字符串长度不超过 200, 可以暴力枚举一个字符串的所有前缀, 然后用kmp去匹配其他字符串.
我这里是用后缀数组写的. 类似 http://www.cnblogs.com/geloutingyu/p/7450580.html
不过本题是有 n 个字符串, 不能直接暴力判断. 不难想到这里可以直接二分答案长度, 不过 check 函数比较难想到, 具体看代码
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#define rank Rank
using namespace std; const int MAXN = 1e6 + ;
int sol;
char str[MAXN];
int SA[MAXN], rank[MAXN], height[MAXN], sum[MAXN], tp[MAXN], vis[MAXN], tag[(int)(4e3 + )]; bool cmp(int *f, int x, int y, int w){
return f[x] == f[y] && f[x + w] == f[y + w];
} void DA(char *s, int n, int m){
for(int i = ; i < m; i++) sum[i] = ;
for(int i = ; i < n; i++) sum[rank[i] = s[i]]++;
for(int i = ; i < m; i++) sum[i] += sum[i - ];
for(int i = n - ; i >= ; i--) SA[--sum[rank[i]]] = i;
for(int len = ; len <= n; len <<= ){
int p = ;
for(int i = n - len; i < n; i++) tp[p++] = i;
for(int i = ; i < n; i++){
if(SA[i] >= len) tp[p++] = SA[i] - len;
}
for(int i = ; i < m; i++) sum[i] = ;
for(int i = ; i < n; i++) sum[rank[tp[i]]]++;
for(int i = ; i < m; i++) sum[i] += sum[i - ];
for(int i = n - ; i >= ; i--) SA[--sum[rank[tp[i]]]] = tp[i];
swap(rank, tp);
p = ;
rank[SA[]] = ;
for(int i = ; i < n; i++){
rank[SA[i]] = cmp(tp, SA[i - ], SA[i], len) ? p - : p++;
}
if(p >= n) break;
m = p;
}
int k = ;
n--;
for(int i = ; i <= n; i++) rank[SA[i]] = i;
for(int i = ; i < n; i++){
if(k) k--;
int j = SA[rank[i] - ];
while(s[i + k] == s[j + k]) k++;
height[rank[i]] = k;
}
} bool check(int mid, int n, int len){
int cnt = ;
memset(tag, , sizeof(tag));
tag[vis[SA[]]] = ;
for(int i = ; i <= len; i++){
if(height[i] >= mid){
if(!tag[vis[SA[i]]]){
cnt++;
tag[vis[SA[i]]] = ;
if(cnt >= n){
sol = SA[i];
return true;
}
}
}else{
cnt = ;
memset(tag, , sizeof(tag));
tag[vis[SA[i]]] = ;
}
}
return false;
} int main(void){
int n;
while(~scanf("%d", &n) && n){
memset(vis, , sizeof(vis));
scanf("%s", str);
int len = strlen(str);
int mx = len;
for(int i = ; i < n; i++){
vis[len] = ;
str[len] = '';
scanf("%s", str + + len);
mx = max(mx, (int)(strlen(str) - len));
len = strlen(str);
}
str[len] = ;
DA(str, len + , 'z' + );
for(int i = ; i <= len; i++) vis[i] += vis[i - ];
int l = , r = mx;
while(l <= r){
int mid = (l + r) >> ;
if(check(mid, n, len)) l = mid + ;
else r = mid - ;
}
if(l - <= ){
puts("IDENTITY LOST");
continue;
}
for(int i = sol, j = ; j <= l - ; i++, j++){
printf("%c", str[i]);
}
puts("");
}
return ;
}
hdu2328(后缀数组 + 二分)的更多相关文章
- BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )
二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...
- BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案
BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案 Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l 读入单 ...
- 【bzoj4310】跳蚤 后缀数组+二分
题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个 ...
- BZOJ 1717 [USACO06DEC] Milk Patterns (后缀数组+二分)
题目大意:求可重叠的相同子串数量至少是K的子串最长长度 洛谷传送门 依然是后缀数组+二分,先用后缀数组处理出height 每次二分出一个长度x,然后去验证,在排序的后缀串集合里,有没有连续数量多于K个 ...
- POJ 1743 [USACO5.1] Musical Theme (后缀数组+二分)
洛谷P2743传送门 题目大意:给你一个序列,求其中最长的一对相似等长子串 一对合法的相似子串被定义为: 1.任意一个子串长度都大于等于5 2.不能有重叠部分 3.其中一个子串可以在全部+/-某个值后 ...
- Poj 1743 Musical Theme(后缀数组+二分答案)
Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...
- Poj 3261 Milk Patterns(后缀数组+二分答案)
Milk Patterns Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk g ...
- HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given ...
- SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)
[题目链接] http://www.spoj.pl/problems/PHRASES/ [题目大意] 求在每个字符串中出现至少两次的最长的子串 [题解] 注意到这么几个关键点:最长,至少两次,每个字符 ...
随机推荐
- MacOS配置Erlang开发环境
Mac下安装Erlang brew 的安装: $ curl -LsSf http://github.com/mxcl/homebrew/tarball/master | sudo tar xvz -C ...
- SpringMVC—对Ajax的处理(含 JSON 类型)(3)
五.服务器端的 SpringMVC 如何返回 JSON 类型的字符串. 请求: $("#testJson8").click(function () { $.ajax({ ...
- nfs cron shell 笔记
1.nfs 2.crond 3.shell 1.准备环境: 防火墙 selinux 配置ip 2.安装软件 二进制 源码安装 3.改改配置文件 二进制:/etc/nginx/nginx.conf 源码 ...
- C++深度解析教程学习笔记(2)C++中的引用
1.C++中的引用 (1)变量名的回顾 ①变量是一段实际连续存储空间的别名,程序中通过变量来申请并命名存储空间 ②通过变量的名字可以使用存储空间.(变量的名字就是变量的值,&变量名是取地址操作 ...
- Android指针管理:RefBase,SP,WP
Android中通过引用计数来实现智能指针,并且实现有强指针与弱指针.由对象本身来提供引用计数器,但是对象不会去维护引用计数器的值,而是由智能指针来管理. 要达到所有对象都可用引用计数器实现智能指针管 ...
- findall查找 ^$*+?{ }{m,n}[].[.] \w \s \d \b \D \W
#!/usr/bin/env python import re r = "aasa da.5a5dfgfda ada" ret = re.findall('a',r) print( ...
- PHP数组函数的使用
1.array_walk($arr, $func, [$data]) 使用用户自定义的函数遍历所有的元素,返回true/false $func是一个函数名 默认会传入两个参数 第一个 $arr的值, ...
- [patl2-001]紧急救援
解题关键:最短路的变形. 1.按顶点存储,$O(n^2)$ #include<cstdio> #include<cstring> #include<algorithm&g ...
- Swing事件机制
-------------siwuxie095 Swing 是基于 MVC 结构的框架 在 Swing 中,所有的用户操作都是基于 Co ...
- 电脑安装unity3d有C盘逐渐爆满问题解决方案
打开unity3d软件,Edit - Preference - GI Cache选中 Custom Cache Location,切换到别的盘,然后点击 Clean Cache清空一次,再查看C盘,存 ...