http://www.spoj.com/problems/PHRASES/

求出后缀数组然后二分。

因为有多组数据,所以倍增求后缀数组时要特判是否越界。

二分答案时的判断要注意优化!

时间复杂度\(O(TnL\log L)\),L为字符串总长度。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int N = 100103; int t1[N << 1], t2[N << 1], c[N]; void st(int *x, int *y, int *sa, int n, int m) {
memset(c, 0, sizeof(int) * (m + 1));
for (int i = 0; i < n; ++i) ++c[x[i]];
for (int i = 1; i <= m; ++i) c[i] += c[i - 1];
for (int i = n - 1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i];
} void mkhz(int *r, int *sa, int n, int m) {
int *x = t1, *y = t2, *t, i, j, p;
for (i = 0; i < n; ++i) y[i] = i, x[i] = r[i];
st(x, y, sa, n, m);
for (j = 1, p = 1; j < n && p < n; m = p - 1) {
for (p = 0, i = n - j; i < n; ++i) y[p++] = i;
for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
st(x, y, sa, n, m);
for (t = x, x = y, y = t, x[sa[0]] = 0, p = 1, i = 1; i < n; ++i)
x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && ((sa[i] + j >= n ? -1 : y[sa[i] + j]) == (sa[i - 1] + j >= n ? -1 : y[sa[i - 1] + j])) ? p - 1 : p++;
}
} void mkh(int *r, int *sa, int *h, int *rank, int n) {
int i, j, k = 0;
for (i = 0; i < n; ++i) rank[sa[i]] = i;
for (i = 1; i < n; h[rank[i++]] = k)
for (k ? --k : k = 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; ++k);
} char s[N];
int r[N], n, id[N], slen, len, sa[N], h[N], rank[N], L[13], R[13], maxl[13], minr[13], used[13]; bool can(int x) {
int left = 1, ret, right, tl, tr, idnow;
while (left <= len) {
for (right = left + 1; h[right] >= x && right <= len; ++right);
--right; if (right - left + 1 < (n << 1)) {left = right + 1; continue;}
ret = 0;
for (int i = 1; i <= n; ++i) maxl[i] = L[i] - 1, minr[i] = R[i] + 1, used[i] = 0;
for (int i = left; i <= right; ++i)
if ((idnow = id[i]) && !used[idnow]) {
tl = sa[i]; tr = tl + x - 1;
if (tr < maxl[idnow] || tl > minr[idnow])
++ret, used[idnow] = 1;
else
maxl[idnow] = max(maxl[idnow], tl), minr[idnow] = min(minr[idnow], tr);
}
if (ret == n) return true; left = right + 1;
}
return false;
} int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%d", &n);
len = 0; int minslen = 0x7ffffff;
for (int i = 1; i <= n; ++i) {
scanf("%s", s);
slen = strlen(s);
minslen = min(minslen, slen);
L[i] = len + 1;
R[i] = len + slen;
for (int j = 0; j < slen; ++j)
r[++len] = s[j];
r[++len] = 200 + i;
}
r[len + 1] = -1; mkhz(r, sa, len + 1, 300);
mkh(r, sa, h, rank, len + 1); for (int i = 1; i <= n; ++i) {
for (int j = L[i], top = R[i]; j <= top; ++j)
id[rank[j]] = i;
id[rank[R[i] + 1]] = 0;
}
int left = 0, mid, right = minslen >> 1;
while (left < right) {
mid = (left + right + 1) >> 1;
if (can(mid)) left = mid;
else right = mid - 1;
}
printf("%d\n", left);
}
return 0;
}

【SPOJ 220】Relevant Phrases of Annihilation的更多相关文章

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

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

  2. 【SPOJ220】Relevant Phrases of Annihilation (SA)

    成功完成3连T!   嗯没错,三道TLE简直爽到不行,于是滚去看是不是模版出问题了..拿了3份其他P党的模版扔上去,嗯继续TLE...蒟蒻表示无能为力了... 思路像论文里面说的,依旧二分长度然后分组 ...

  3. 【SPOJ220】Relevant Phrases of Annihilation(后缀数组,二分)

    题意: n<=10,len<=1e4 思路: #include<cstdio> #include<cstring> #include<string> # ...

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

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

  5. SPOJ - PHRASES K - Relevant Phrases of Annihilation

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

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

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

  7. 【 SPOJ - GRASSPLA】 Grass Planting (树链剖分+树状数组)

    54  种草约翰有 N 个牧场,编号为 1 到 N.它们之间有 N − 1 条道路,每条道路连接两个牧场.通过这些道路,所有牧场都是连通的.刚开始的时候,所有道路都是光秃秃的,没有青草.约翰会在一些道 ...

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

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

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

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

随机推荐

  1. 【usaco-Liars and Truth Tellers, 2013 Jan真假奶牛】并查集

    题解: 原先我看错题了,以为是任意选择k个使得它们不矛盾. 这样的话怎么做呢?我想M^2判断,把它们分成若干个集合,集合里面两两不矛盾这个集合里所有的话就不矛盾了. 但是这样是错的.为什么呢? 每一句 ...

  2. Html5学习3(拖放、Video(视频)、Input类型(color、datetime、email、month 、number 、range 、search、Tel、time、url、week ))

    1.Html拖放 <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> < ...

  3. Python 对象的深拷贝与浅拷贝 -- (转)

    本文内容是在<Python核心编程2>上看到的,感觉很有用便写出来,给大家参考参考! 浅拷贝 首先我们使用两种方式来拷贝对象,一种是切片,另外一种是工厂方法.然后使用id函数来看看它们的标 ...

  4. 时间盲注脚本.py

    时间盲注脚本 #!/usr/bin/env python # -*- coding: utf-8 -*- import requests import time payloads = 'abcdefg ...

  5. Mysql安装发生「Access denied for user ‘root’@’localhost’ (using password: NO)」错误

    参考:http://www.aipacommander.com/entry/2014/05/26/152247 mysql_secure_installation 依赖重置密码

  6. 高性能网络编程(1)—accept建立连接‍(待研究)

    阿里云博客上一篇感觉还不错的文章,待研究,原文链接如下: http://blog.aliyun.com/673?spm=5176.7114037.1996646101.3.oBgpZQ&pos ...

  7. java生成缩略图,旋转,水印,截图

    转自:http://rensanning.iteye.com/blog/1545708 感谢,方便自己查看

  8. hive的窗口函数1

    Hive中提供了越来越多的分析函数,用于完成负责的统计分析.抽时间将所有的分析窗口函数理一遍,将陆续发布.今天先看几个基础的,SUM.AVG.MIN.MAX.用于实现分组内所有和连续累积的统计. 1. ...

  9. 【hdoj_1085】Holding Bin-Laden Captive![母函数]

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1085 可以这样理解题意:给出1元,2元和5元的三种硬币若干,每种硬币数量给出,现在可以从所有的硬币中,选出 ...

  10. OpenAcc笔记——update

    program main use omp_lib use openacc implicit none real,allocatable:: v1(:) integer length, idx call ...