题目

http://poj.org/problem?id=3080

题意

有m个(2<=m<=10)不包含空格的字符串,长度为60个字符,求所有字符串中都出现过的最长公共子序列,若该子序列长度小于3,输出"no significant commonalities",否则,输出字典序最小且长度最大的公共子序列。

思路

由于数据较小,其实可以使用比较暴力的思路,但这里为了复习后缀数组采用后缀数组的方法。

1. 将多个字符串合为一个目标字符串buff,为了防止程序无法分清字符串连接处,每个连接处添加一个空格,形如AAAA GGGG。

2. 建立后缀数组,这里采用基数排序的方法。

a. 令rk数组记录后缀的字典序排名,也即rk[i]为从第i个字符开始的后缀的字典序排名,排名从0开始。

b. 令sa数组记录排序后的后缀,也即sa[i]为字典序第i的后缀的第一个字符的位置,例如buff='abba',则sa[0]=4代表空串,sa[1]=3代表a,sa[2]=0代表abba,依次类推。

c. 进行基数排序的初始排序,排序第一个字符。

d. 初始化跨度k为1,每次完成下面的循环,k乘以2倍,也即每次通过目前的rk数组把已经排序的部分长度扩展2倍。

e. 用基数排序对后缀[k,2k]进行排序。

解释:此时后缀[0,k]有序,也即前k个字符一定是按照字母序排序的,举例来说,排序可能是这样,k=2:空串,a,aadd,aacc,abaa,abcc。

此时后面k个字符,也即[k,2k]部分是无序的,但是[k,2k]部分的顺序可以和[0,k]部分一一对应起来,因为[k,2k]部分如果不是空串,那么一定是另一个后缀的[0,k]部分。

这一步根据这种关系将后缀数组sa排列为[k,2k]为主键,[0,k]为第二位键字典序递增顺序。

f. 用基数排序对后缀[0,k]进行排序。

解释:由于上一步排列的顺序,根据基数排序的特点,后缀数组将会变为[0.k]为主键,[k,2k]为第二位键字典序递增顺序,也即[0,2k]遵从字典序排列。

g. 根据sa计算rk,此处若两个后缀[0,2k]部分相同,则对应rk也应当相同。

h. 循环直至k >= len,此时明显全部遵从字典序排列。

i. 根据sa计算rk,此处rk[sa[i]] = i,此时rk的含义将发生改变,变为sa的索引,注意此处若两个后缀[0,2k]相同,其对应rk不相同。

3. 建立高度数组h。(对于从i开始的后缀,如果其高度(即该后缀和在字典序上最接近它且比它字典序小的那个后缀的公共前缀长度)为height,那么i+1开始的后缀高度至少为height-1,利用这一性质,以字符串原有的顺序遍历后缀并且计算其高度。)

4. 得出答案,由题意,设答案的长度为ans,第一个字符是目标串的第start个字符,则h数组中一定有一段连续的子序列都大于等于ans,且对应的后缀分别来自目标字符串的m段。

a. 建立优先队列,用于存储后缀的高度和index,并获知在当前扫描的这一段中出现过的最小高度。

b. 用cnt数组监视当前扫描的这一段中每段有多少个后缀出现。可以通过cnt数组获知被扫描的这一段中目标段中有多少段的后缀出现过,设这个值为num。

c. 设起点为s,若目标串长度为len,则s从0循环至len,对每次循环:

i. 初始化e=s+1,e不断向后扫,h[s,e]即为当前被扫描的段,直到num==m。

ii.将最小高度与目前存储的ans进行比较,若最小高度较大,则ans赋值为最小高度,start赋值为s。

解释:由于rk和h是对应的,所以start被赋予的会是字典序最小长度最长的公共子序列的rk,可以通过sa输出答案。

感想

这道题卡在三个点上:1. 基数排序,先对后半段排序,再对前半段排序。

2. 基数排序,因为在排序过程中将len加入排序,导致边界出错。

3. 基数排序,因为rk是对应于目标串的位置的,所以先对后半段排序时不用改变rk。

代码

 #include <cstdio>
#include <map>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <iostream>
#include <assert.h>
#include <sstream>
#include <cctype>
#include <queue>
#include <stack>
#include <map>
#include <iterator>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
typedef unsigned long long ull;
typedef long long ll;
typedef long double ld; const int basenum = ;
const int basenump1 = basenum + ;
const int maxm = ;
const int maxn = basenump1 * maxm + basenump1; char buff[maxn]; int m;
int len; int rk[maxn];
int trk[maxn];
int sa[maxn];
int tsa[maxn];
int cnt[maxn];
int h[maxn]; void debugrk(int *sa, int l){
for(int i = ;i <= len;i++){
printf("rk[%d]:%d ",i,rk[i]);
for(int j = i;j < len && j < i + l;j++){
putchar(buff[j]);
}
puts("");
}
puts("");
} void debugsa(int *sa, int l){
for(int i = ;i <= len;i++){
printf("sa[%d]:%d rk %d ",i,sa[i], rk[sa[i]]);
for(int j = sa[i];j < len && j < sa[i] + l;j++){
putchar(buff[j]);
}
puts("");
}
puts("");
} void debugh(){
for(int i = ;i <= len;i++){
printf("POS: %d h[%d]:%d ", sa[i],i,h[i]);
for(int j = sa[i];j < len;j++){
putchar(buff[j]);
}
puts("");
}
puts("");
} void input()
{
scanf("%d",&m);
len = m * basenump1 - ;
for(int i = ; i < m; i++)
{
scanf("%s", buff + i * basenump1);
if(i + < m)buff[i * basenump1 + basenum] = ' ';
}
} void build()
{
memset(rk, , sizeof rk);
memset(cnt, , sizeof cnt);
rk[len] = trk[len] = ;
sa[] = tsa[] = len;
for(int i = ; i < len; i++)
{
rk[i] = buff[i];
cnt[rk[i]]++;
}
// first radix sort
for(int i = ; i < ; i++)
{
cnt[i] += cnt[i - ];
}
for(int i = len - ; i >= ; i--)
{
sa[cnt[rk[i]]--] = i;
}
for(int k = ; k < len; k <<= )
{
memset(cnt, , sizeof cnt);
for(int i = ; i < len; i++)
{
cnt[(i + k < len)?rk[i + k]:]++;
}
/*
Or you can use
for(int i = len;i > 0;i--){
cnt[(sa[i] + k < len)?rk[sa[i] + k]:0]++;
}
*/
for(int i = ; i <= len; i++)
{
cnt[i] += cnt[i - ];
}
for(int i = len; i > ; i--)
{
int ind = cnt[(sa[i] + k < len)?rk[sa[i] + k]:]--;
tsa[ind] = sa[i];
}
memset(cnt, , sizeof cnt);
for(int i = ; i < len; i++)
{
cnt[rk[i]]++;
}
/*
Or you can use
for(int i = len;i > 0;i--){
cnt[rk[sa[i]]]++;
}
*/
for(int i = ; i <= len; i++)
{
cnt[i] += cnt[i - ];
}
for(int i = len; i > ; i--)
{
int ind = cnt[rk[tsa[i]]]--;
sa[ind] = tsa[i];
}
for(int i = , now = sa[i], former = sa[i - ]; i <= len; i++, now = sa[i], former = sa[i - ])
{
trk[now] = trk[former];
int nownxt = min(now + k, len);
int formernxt = min(former + k, len);
if(rk[now] != rk[former] || rk[nownxt] != rk[formernxt]){ trk[now]++;
}
}
for(int i = ; i < len; i++)
{
rk[i] = trk[i];
}
}
for(int i = ;i <= len;i++){
rk[sa[i]] = i;
}
memset(h, , sizeof h);
//debugsa(sa, len);
//debugrk(sa, len);
for(int i = , height = ; i < len; i++)
{
if(height)height--;
int former = sa[rk[i] - ];
while(i + height < len && former + height < len && buff[i + height] == buff[former + height])height++;
h[rk[i]] = height;
}
//debugh();
} void solve()
{
build();
memset(cnt, , sizeof cnt);
priority_queue<P, vector<P>, greater<P> >que;
int num = ;
int ans = ;
int start = ;
for(int s = ,e = ; s <= len; s++)
{
while(num < m && e <= len)
{
que.push(P(h[e], e));
int ind = sa[e] / basenump1;
if(cnt[ind] == )num++;
cnt[ind]++;
e++;
}
while(que.top().second < s){
que.pop();
}
if(num == m && ans < que.top().first)
{
ans = que.top().first;
start = s - ;
}
if(s > ){
int ind = sa[s - ] / basenump1;
if(cnt[ind] == )num--;
cnt[ind]--;
}
}
if(ans < )puts("no significant commonalities");
else
{
for(int i = ; i < ans; i++)
{
putchar(buff[sa[start] + i]);
}
putchar('\n');
}
} int main()
{
freopen("input.txt", "r", stdin);
int t;
scanf("%d", &t);
for(int ti = ; ti < t; ti++)
{
input();
solve();
}
return ;
}

POJ 3080 Blue Jeans 后缀数组, 高度数组 难度:1的更多相关文章

  1. POJ 3080 Blue Jeans (后缀数组)

    题目大意: 求出这些DNA序列中的最长且字典序最小的公共子串. 思路分析: 二分长度的答案,去height中扫描这个长度是否满足,一旦满足就立即输出.这样就能够保证字典序最小了. #include & ...

  2. POJ 3080 Blue Jeans (求最长公共字符串)

    POJ 3080 Blue Jeans (求最长公共字符串) Description The Genographic Project is a research partnership between ...

  3. poj 3080 Blue Jeans

    点击打开链接 Blue Jeans Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10243   Accepted: 434 ...

  4. POJ 3080 Blue Jeans (字符串处理暴力枚举)

    Blue Jeans  Time Limit: 1000MS        Memory Limit: 65536K Total Submissions: 21078        Accepted: ...

  5. POJ 3080 Blue Jeans(Java暴力)

    Blue Jeans [题目链接]Blue Jeans [题目类型]Java暴力 &题意: 就是求k个长度为60的字符串的最长连续公共子串,2<=k<=10 规定: 1. 最长公共 ...

  6. POJ 3080 Blue Jeans 找最长公共子串(暴力模拟+KMP匹配)

    Blue Jeans Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 20966   Accepted: 9279 Descr ...

  7. POJ 3080 Blue Jeans(后缀数组+二分答案)

    [题目链接] http://poj.org/problem?id=3080 [题目大意] 求k个串的最长公共子串,如果存在多个则输出字典序最小,如果长度小于3则判断查找失败. [题解] 将所有字符串通 ...

  8. POJ 3080 Blue Jeans、POJ 3461 Oulipo——KMP应用

    题目:POJ3080 http://poj.org/problem?id=3080 题意:对于输入的文本串,输出最长的公共子串,如果长度相同,输出字典序最小的. 这题数据量很小,用暴力也是16ms,用 ...

  9. poj 3080 Blue Jeans 解题报告

    题目链接:http://poj.org/problem?id=3080 该题属于字符串处理中的串模式匹配问题.题目要求我们:给出一个DNA碱基序列,输出最长的相同的碱基子序列.(保证在所有的序列中都有 ...

随机推荐

  1. Codeforces 444 C - DZY Loves Colors

    C - DZY Loves Colors 思路: 分块,复杂度有点玄学,和普通分块不同的是在这个块被一次染色的时候暴力染整个块. 代码: #pragma GCC optimize(2) #pragma ...

  2. Asp.net core 学习笔记 ( Identity 之 Authentication )

    和从前的 identity 区别不是很大. 从 2.1 开始 vs 模板的 identity 都被封装了起来, 你几乎看不到任何一行代码, 需要向下面这样打开它, 才能做修改. 说一下比较常用的配置 ...

  3. RabbitMQ消费方式汇总

    在学习本章节前,请先学习之前的章节:Java访问RabbitMQ:https://www.cnblogs.com/duanjt/p/10057330.htmlRabbitMQ消息发布时的权衡:http ...

  4. laravel配置路由除了 / 都是404解决办法

    1.php.ini开启phpopenssl 2.conf  (nginx为例) location / { index index.html index.htm index.php l.php; #tr ...

  5. boke例子:用户登录

    boke例子:用户登录 1.首先创建user表,authority表(角色),user_authority,表(用户角色表) Authority实体类,需要继承:GrantedAuthority类, ...

  6. 雷林鹏分享: XML CDATA

    XML CDATA XML 文档中的所有文本均会被解析器解析. 只有 CDATA 区段中的文本会被解析器忽略. PCDATA - 被解析的字符数据 XML 解析器通常会解析 XML 文档中所有的文本. ...

  7. English trip M1 - AC11 May I Help You? 我能帮到你吗? Teacher:Lamb

    In this lesson you will learn to ask for things in shops  在本课程中,您将学习如何在商店中寻找东西 课上内容(Lesson) How are ...

  8. 20171022xlVBA练手提取入所记录

    Sub GetWordText改进() Dim Wb As Workbook Dim Sht As Worksheet Dim Rng As Range Dim wdApp As Object Dim ...

  9. Practical Node.js摘录(2018版)第1,2章。

    大神的node书,免费 视频:https://node.university/courses/short-lectures/lectures/3949510 另一本书:全栈JavaScript,学习b ...

  10. Spring Batch 使用场景

    一个标准的批处理程序通常会从数据库,文件或者队列中读取大量的数据和记录,然后对获取的数据进行处理,然后将修改后的格式写回到数据库中. 通常 Spring Batch 在离线模式下进行工作,不需要用户干 ...