题目链接:http://www.spoj.com/problems/PHRASES/en/

题意:给定n个字符串,求一个最长的子串至少在每个串中的不重叠出现次数都不小于2。输出满足条件的最长子串长度

思路:根据<<后缀数组——处理字符串的有力工具>>的思路,先将 n个字符串连起来, 中间用不相同的且没有出现在字符串中的字符隔开, 求后缀数组。 然后二分答案, 再将后缀分组。判断的时候, 要看是否有一组后缀在每个原来的字符串中至少出现两次, 并且在每个原来的字符串中, 后缀的起始位置的最大值与最小值之差是否不小于当前答案(判断能否做到不重叠, 如果題目中没有不重叠的要求, 那么不用做此判断) 。这个做法的时间复杂度为 0(nlogn) 。

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<time.h>
#include<cmath>
#include<set>
using namespace std;
typedef long long int LL;
const int MAXN = * * ;
int wa[MAXN], wb[MAXN], wv[MAXN], WS[MAXN];
int cmp(int *r, int a, int b, int l)
{
return r[a] == r[b] && r[a + l] == r[b + l];
}
void da(int *r, int *sa, int n, int m)
{
int i, j, p, *x = wa, *y = wb, *t;
for (i = ; i < m; i++) WS[i] = ;
for (i = ; i < n; i++) WS[x[i] = r[i]]++;
for (i = ; i < m; i++) WS[i] += WS[i - ];
for (i = n - ; i >= ; i--) sa[--WS[x[i]]] = i;
for (j = , p = ; p < n; j *= , m = p)
{
for (p = , i = n - j; i < n; i++) y[p++] = i;
for (i = ; i < n; i++) if (sa[i] >= j) y[p++] = sa[i] - j;
for (i = ; i < n; i++) wv[i] = x[y[i]];
for (i = ; i < m; i++) WS[i] = ;
for (i = ; i < n; i++) WS[wv[i]]++;
for (i = ; i < m; i++) WS[i] += WS[i - ];
for (i = n - ; i >= ; i--) sa[--WS[wv[i]]] = y[i];
for (t = x, x = y, y = t, p = , x[sa[]] = , i = ; i < n; i++)
x[sa[i]] = cmp(y, sa[i - ], sa[i], j) ? p - : p++;
}
return;
}
int Rank[MAXN], height[MAXN], sa[MAXN];
void calheight(int *r, int *sa, int n){
int i, j, k = ;
for (i = ; i <= n; i++) { Rank[sa[i]] = i; }
for (i = ; i < n; height[Rank[i++]] = k){
for (k ? k-- : , j = sa[Rank[i] - ]; r[i + k] == r[j + k]; k++);
}
return;
}
int r[MAXN], len, n, t, Index[MAXN],vis[MAXN];
char sub[+];
struct Node{
int cnt,maxsa, minsa;
void init(){cnt = , maxsa = -, minsa = MAXN;}
}node[];
bool check(int x){
int tot = ,idx,Lidx;
for (int i = ; i <= n; i++){
node[i].init();
}
memset(vis, , sizeof(vis));
for (int i = ; i < len; i++){
//heigth[i]是sa[i]和sa[i-1]的LCP
idx = Index[sa[i]], Lidx = Index[sa[i - ]];
if (i == len - ){
for (int k = ; k <= n; k++){
//判断每个字符串的出现次数和后缀的起始位置的最大值和最小值的差是否不小于x
if (node[k].cnt >= && node[k].maxsa - node[k].minsa >= x){
tot++;
}
node[k].init();
}
if (tot == n){ return true; }//n个串都满足要求,说明长度x存在
tot = ;
break;
}
if (height[i] >= x){
if (!vis[i]){//每个后缀只算一次
vis[i] = ; node[idx].cnt++; //记录后缀在该组出现的次数
node[idx].maxsa = max(node[idx].maxsa, sa[i]);//最大值
node[idx].minsa = min(node[idx].minsa, sa[i]);//最小值
}
if (!vis[i-]){
vis[i - ] = ; node[Lidx].cnt++;
node[Lidx].maxsa = max(node[Lidx].maxsa, sa[i-]);
node[Lidx].minsa = min(node[Lidx].minsa, sa[i-]);
}
}
else{
for (int k = ; k <= n; k++){
//判断每个字符串的出现次数和后缀的起始位置的最大值和最小值的差是否不小于x
if (node[k].cnt >= &&node[k].maxsa-node[k].minsa>=x){
tot++;
}
node[k].init();
}
if (tot == n){ return true;} //n个串都满足要求,说明长度x存在
tot = ;
}
}
return false;
}
void solve(){
int L = , R = /, mid, ans = ;
while (R >= L){
mid = (L + R) / ;
if (check(mid)){
ans = mid;
L = mid + ;
}
else{
R = mid - ;
}
}
printf("%d\n", ans);
}
int main(){
//#ifdef kirito
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
//#endif
// int start = clock();
scanf("%d", &t);
while (t--){
scanf("%d", &n); len = ;
for (int i = , val = ; i <= n; i++, val++){
scanf("%s", &sub);
for (int j = ; j < strlen(sub); j++){
Index[len] = i; //记录每个拼接后每个位置属于原输入的哪个
r[len++] = (sub[j] - 'a' + n + );
}
Index[len] = i;
r[len++] = val;
}
da(r, sa, len, );
calheight(r, sa, len - );
solve();
}
//#ifdef LOCAL_TIME
// cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
return ;
}

SPOJ PHRASES 后缀数组的更多相关文章

  1. SPOJ REPEATS 后缀数组

    题目链接:http://www.spoj.com/problems/REPEATS/en/ 题意:首先定义了一个字符串的重复度.即一个字符串由一个子串重复k次构成.那么最大的k即是该字符串的重复度.现 ...

  2. SPOJ SUBST1 后缀数组

    题目链接:http://www.spoj.com/problems/SUBST1/en/ 题意:给定一个字符串,求不相同的子串个数. 思路:直接根据09年oi论文<<后缀数组——出来字符串 ...

  3. SPOJ DISUBSTR 后缀数组

    题目链接:http://www.spoj.com/problems/DISUBSTR/en/ 题意:给定一个字符串,求不相同的子串个数. 思路:直接根据09年oi论文<<后缀数组——出来字 ...

  4. Spoj-DISUBSTR - Distinct Substrings~New Distinct Substrings SPOJ - SUBST1~(后缀数组求解子串个数)

    Spoj-DISUBSTR - Distinct Substrings New Distinct Substrings SPOJ - SUBST1 我是根据kuangbin的后缀数组专题来的 这两题题 ...

  5. SPOJ DISUBSTR ——后缀数组

    [题目分析] 后缀数组模板题. 由于height数组存在RMQ的性质. 那么对于一个后缀,与前面相同的串总共有h[i]+sa[i]个.然后求和即可. [代码](模板来自Claris,这个板子太漂亮了) ...

  6. [spoj DISUBSTR]后缀数组统计不同子串个数

    题目链接:https://vjudge.net/contest/70655#problem/C 后缀数组的又一神奇应用.不同子串的个数,实际上就是所有后缀的不同前缀的个数. 考虑所有的后缀按照rank ...

  7. Distinct Substrings SPOJ - DISUBSTR 后缀数组

    Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...

  8. SPOJ 694 (后缀数组) Distinct Substrings

    将所有后缀按照字典序排序后,每新加进来一个后缀,它将产生n - sa[i]个前缀.这里和小罗论文里边有点不太一样. height[i]为和字典序前一个的LCP,所以还要减去,最终累计n - sa[i] ...

  9. spoj 694(后缀数组)

    题意:求一个字符串的不重复子串的个数. 分析:对于下标为i的位置,能够产生的前缀子串个数为len-i(下标从0开始),对于与它字典序相邻的后缀产生的子串是重复的(就是他们的最长公共前缀),所以我们要减 ...

随机推荐

  1. sqlserver insert 存储过程

    -- 根据表中数据生成insert语句的存储过程Create Proc proc_insert (@tablename varchar(256))  as                        ...

  2. android中判断网络连接是否可用

    一.判断网络连接是否可用 public static boolean isNetworkAvailable(Context context) { ConnectivityManager cm = (C ...

  3. qt编译mysql插件

    安装MySQL,C:\Program Files (x86)\MySQL\MySQL Server 5.7,然后把include和lib文件夹拷贝到C盘,因为qmake不允许路径中有空格!!! 安装Q ...

  4. poj1456(贪心+并查集)

    题目链接: http://poj.org/problem?id=1456 题意: 有n个商品, 已知每个商品的价格和销售截止日期, 每销售一件商品需要花费一天, 即一天只能销售一件商品, 问最多能买多 ...

  5. PHP之MVC项目实战

    本文主要包括以下内容 类文件自动加载 路径管理 页面跳转 注册自动加载方法 配置文件系统 cookie session 类文件自动加载 在PHP中使用别的类时,需要载入类文件,如果类很多的话,需要重复 ...

  6. 重温WCF之构建一个简单的WCF(一)(2)通过Windows Service寄宿服务和WCF中实现操作重载

    参考地址:http://www.cnblogs.com/zhili/p/4039111.html 一.如何在Windows Services中寄宿WCF服务 第一步:创建Windows 服务项目,具体 ...

  7. 【翻译四】java-并发之线程暂停

    Pausing Execution with Sleep Thread.sleep causes the current thread to suspend execution for a speci ...

  8. .NET Nancy 详解(四) Self Host

    Self Host 使得Nancy 能够在任意application 中启动,无论是console 还是windows service.这期我们使用的版本是Nancy v0.4.0. Demo 首先看 ...

  9. [Linux] 解决终端显示乱码问题

    [背景] 公司弄了两台新的虚拟机,用来将原先都部署在一台机器上的JIRA, Fisheye, Confluence迁移到这两台机器上,使用SecureCRT进行登录,使用相关命令时,一台出现乱码,另外 ...

  10. 一些常用的C++标准函数

    一些常用的C++标准函数 double atof(const char* p); int atoi(const char* p); long atol(const char* p); cstdlib ...