题目链接: 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(后缀数组 + 二分)的更多相关文章

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

    二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...

  2. BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案

    BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案 Description          给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l        读入单 ...

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

    题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个 ...

  4. BZOJ 1717 [USACO06DEC] Milk Patterns (后缀数组+二分)

    题目大意:求可重叠的相同子串数量至少是K的子串最长长度 洛谷传送门 依然是后缀数组+二分,先用后缀数组处理出height 每次二分出一个长度x,然后去验证,在排序的后缀串集合里,有没有连续数量多于K个 ...

  5. POJ 1743 [USACO5.1] Musical Theme (后缀数组+二分)

    洛谷P2743传送门 题目大意:给你一个序列,求其中最长的一对相似等长子串 一对合法的相似子串被定义为: 1.任意一个子串长度都大于等于5 2.不能有重叠部分 3.其中一个子串可以在全部+/-某个值后 ...

  6. Poj 1743 Musical Theme(后缀数组+二分答案)

    Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...

  7. Poj 3261 Milk Patterns(后缀数组+二分答案)

    Milk Patterns Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk g ...

  8. HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given ...

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

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

随机推荐

  1. Nunit 2.6 无法调试.Net Framework 4.0

    <configuration> <!-- The GUI only runs under .NET 2.0 or higher. The useLegacyV2RuntimeActi ...

  2. RCE、exp、Exploit、Exploit Pack、exp-gui、Payload、MetaSploit都是啥

    对于走在安全路上的小菜来说,这几个exp.Exploit.Exploit Pack.exp-gui.Payload.MetaSploit名词着实把人转的不轻,下面给大家解释下: RCE,remote ...

  3. 数据库:sql 多表联合更新【转】

    SQL Update多表联合更新的方法 (1) sqlite 多表更新方法 update t1 set col1=t2.col1 from table1 t1 inner join table2 t2 ...

  4. paramiko 模块封装

    #!/usr/bin/env python#coding=utf-8 import paramiko, getpass,sys,traceback class ssh_utils(): def log ...

  5. 程序中使用log4J打印信息的两种方式

    (1)通过org.apache.commons.logging.Log 接口实例化: public static Log log = LogFactory.getLog(String name); p ...

  6. 10-31SQLserver基础--聚合函数、分组

    在查询语句时,也存在一些方法和属性,而这些方法在查询时统称为函数,便利查询时使用 聚合函数(都是针对字段操作) 聚合是缩减一系列输入值的表达式,例如缩减为单个值. Select*from biao 1 ...

  7. Python 标准库 -> Pprint 模块 -> 用于打印 Python 数据结构

    使用 pprint 模块 pprint 模块( pretty printer ) 用于打印 Python 数据结构. 当你在命令行下打印特定数据结构时你会发现它很有用(输出格式比较整齐, 便于阅读). ...

  8. 类型:.net;问题:ASP.NET路由;结果:ASP.NET 路由 .NET Framework 4

    ASP.NET 路由 .NET Framework 4   更新:2007 年 11 月 ASP.NET 路由使您可以使用不必映射到网站中特定文件的 URL.由于 URL 不必映射到文件,所以可以在 ...

  9. Excel向数据库插入数据和数据库向Excel导出数据

    为了熟悉java里工作簿的相关知识点,所以找了“Excel向数据库插入数据和数据库向Excel导出数据”的功能来实现. 注意事项:1,mysql数据库: 2,需要导入的jar包有 jxl.jar,my ...

  10. C语言学习笔记--数组参数和指针参数

    1. 数组参数退化为指针的意义 (1)C 语言中只会以值拷贝的方式传递参数,当向函数传递数组时,将整个数组拷贝一份传入函数导致执行效率低下,C 语言以高效作是最初的设计目标,所以这种方法是不可取的. ...