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. 深入浅出MyBatis:JDBC和MyBatis介绍

    JDBC相关概念 Java程序都是通过JDBC连接数据库的,通过SQL对数据库编程,JDBC是由SUN公司提出的一些列规范,只定义了接口规范,具体实现由各个数据库厂商去实现,它是一种典型的桥接模式. ...

  2. spring项目中web-inf下不能引用页面资源

    1.spring项目结构 2.spring结构说明 web-inf目录是不对外开放的,外部没办法直接访问到(即通过url访问),只有通过映射来访问,如映射一个action或servlet通过服务器端跳 ...

  3. ImportError: libQtTest.so.4: cannot open shared

    错误: import cv2 File , in <module> from .cv2 import * ImportError: libQtTest.so.: cannot open s ...

  4. python面向对象进阶(下)

    一.item系列:就是把字典模拟成一个字典去操作(操作字典就用item的方式) obj[‘属性’]的方式去操作属性时触发的方法 __getitem__:obj['属性'] 时触发 __setitem_ ...

  5. 【Python项目】使用Face++的人脸识别detect API进行本地图片情绪识别并存入excel

    准备工作 首先,需要在Face++的主页注册一个账号,在控制台去获取API Key和API Secret. 然后在本地文件夹准备好要进行情绪识别的图片/相片. 代码 介绍下所使用的第三方库 ——url ...

  6. linux===linux后台运行和关闭、查看后台任务(转)

    fg.bg.jobs.&.ctrl + z都是跟系统任务有关的,虽然现在基本上不怎么需要用到这些命令,但学会了也是很实用的 一.& 最经常被用到这个用在一个命令的最后,可以把这个命令放 ...

  7. 2016多校第4场 HDU 6076 Security Check DP,思维

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6076 题意:现要检查两条队伍,有两种方式,一种是从两条队伍中任选一条检查一个人,第二种是在每条队伍中同 ...

  8. OC 01 类和对象

    一.  定义OC的类和创建OC的对象 接下来就在OC中模拟现实生活中的情况,创建一辆车出来.首先要有一个车子类,然后再利用车子类创建车子对象 要描述OC中的类稍微麻烦一点,分2大步骤:类的声明.类的实 ...

  9. KettleDB连接jdbc连接池参数介绍

    http://sheng8407-sina-com.iteye.com/blog/1163245 http://blog.csdn.net/dingxingmei/article/details/41 ...

  10. [New learn]GCD其他方法的使用

    https://github.com/xufeng79x/GCDDemo 1.简介 在前面的两篇博文中我介绍了GCD的一般使用方法和死锁的分析调查.本博文中继续讲解GCD的其他比较常用的几个使用方法. ...