【SPOJ 220】Relevant Phrases of Annihilation
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的更多相关文章
- 【SPOJ 220】 PHRASES - Relevant Phrases of Annihilation
[链接]h在这里写链接 [题意] 给你n(n<=10)个字符串. 每个字符串长度最大为1e4; 问你能不能找到一个子串. 使得这个子串,在每个字符串里面都不想交出 ...
- 【SPOJ220】Relevant Phrases of Annihilation (SA)
成功完成3连T! 嗯没错,三道TLE简直爽到不行,于是滚去看是不是模版出问题了..拿了3份其他P党的模版扔上去,嗯继续TLE...蒟蒻表示无能为力了... 思路像论文里面说的,依旧二分长度然后分组 ...
- 【SPOJ220】Relevant Phrases of Annihilation(后缀数组,二分)
题意: n<=10,len<=1e4 思路: #include<cstdio> #include<cstring> #include<string> # ...
- 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 - PHRASES Relevant Phrases of Annihilation —— 后缀数组 出现于所有字符串中两次且不重叠的最长公共子串
题目链接:https://vjudge.net/problem/SPOJ-PHRASES PHRASES - Relevant Phrases of Annihilation no tags You ...
- 【 SPOJ - GRASSPLA】 Grass Planting (树链剖分+树状数组)
54 种草约翰有 N 个牧场,编号为 1 到 N.它们之间有 N − 1 条道路,每条道路连接两个牧场.通过这些道路,所有牧场都是连通的.刚开始的时候,所有道路都是光秃秃的,没有青草.约翰会在一些道 ...
- 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 ...
随机推荐
- 「6月雅礼集训 2017 Day5」吃干饭
[题目大意] 询问[L,R]中选若干个数异或起来得到的答案集合大小.多组数据. 对于50%的数据,$R - L \leq 10^4$ 对于100%的数据,$R - L \leq 10^{18}, T ...
- iOS开发者两分钟学会用GitHub在Mac上托管代码的两种方法
原文发布者:http://blog.csdn.net/duxinfeng2010 在Mac上使用Xcode进行iOS-Apple苹果iPhone手机开发过程中少不了使用GitHub在Mac上托 ...
- hdu 1863 畅通工程 (并查集+最小生成树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1863 畅通工程 Time Limit: 1000/1000 MS (Java/Others) M ...
- KVM虚拟机建立快照
部分转载: http://blog.csdn.net/gg296231363/article/details/6899533 windows虚拟机默认镜像格式为raw,快照默认格式为qcow2.win ...
- Linux Platform驱动模型(二) _驱动方法【转】
转自:http://www.cnblogs.com/xiaojiang1025/archive/2017/02/06/6367910.html 在Linux设备树语法详解和Linux Platform ...
- Keepalived 安装与简单配置
Keepalived 安装与简单配置 http://sivxy.lofter.com/post/1d21ebb9_7e15000
- python并发模块之concurrent.futures(一)
Python3.2开始,标准库为我们提供了concurrent.futures模块,它提供了ThreadPoolExecutor和ProcessPoolExecutor两个类,实现了对threadin ...
- 【bzoj4562】HAOI2016食物链
记忆化搜索水过去了…… QwQ #include<bits/stdc++.h> #define N 400010 typedef long long ll; using namespace ...
- C++——初识C++
1. C关键字 auto int double long char float short signed unsigned struct union enum static switch case d ...
- Laravel artisan commands
使用php artisan list 可以看到artisan的所有命令以及选项. 当然你也可以在此基础上扩展自己的命令. 1. key 1.1 key:generate 这是一个加密秘钥,用于保证安全 ...