题意:给两个字符串,求一个最短的子串。使得这个子串在两个字符串中出现的次数都等于1.出现的定义为:能够重叠的出现。

解法:后缀数组的应用。从小枚举长度。假设一个长度len合法的话:则一定存在这个样的sa[i]排名。sa[i]与s[i+1]的公共前缀长度大于等于len,且sa[i]与[i-1]的公共前缀长度小于len,同一时候sa[i+1]与[i+2]的公共前缀长度小于len,同一时候保证sa[i]与sa[i+1]在两个串中。Judge函数就是技巧性地实现了这些推断。

代码:

#include<iostream>
#include<string>
#include <cstring>
#include <string.h>
#include <stdio.h>
using namespace std;
const int MAX = 200100; int n, num[MAX];
int sa[MAX], Rank[MAX], height[MAX];//sa[i]表示排名第i的后缀的位置,height[i]表示后缀SA[i]和SA[i-1]的最长公共前缀
int wa[MAX], wb[MAX], wv[MAX], wd[MAX];//名次数组 Rank[i] 保存的是 Suffix(i) 在全部后缀中从小到大排列的 “ 名次 ” 。
//简单的说,后缀数组(SA)是 “ 排第几的是谁? ” ,名次数组(RANK)是 “ 你排第几? ” 。 easy看出,后缀数组和名次数组为互逆运算。 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 n, int m) // 倍增算法0(nlgn)。
{
int i, j, p, *x = wa, *y = wb, *t;
for(i = 0; i < m; i ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i;
for(j = 1, p = 1; p < n; j *= 2, m = p)
{
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;
for(i = 0; i < n; i ++) wv[i] = x[y[i]];
for(i = 0; i < m; i ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[wv[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i];
for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++)
{
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1: p ++;
}
}
} void calHeight(int *r, int n) // 求height数组。
{
int i, j, k = 0;
for(i = 0; i < n; i ++) Rank[sa[i]] = i;
for(i = 0; i < n; height[Rank[i ++]] = k)
{
for(k ? k -- : 0, j = sa[Rank[i]-1]; r[i+k] == r[j+k]; k ++);
}
} int len1=0;
int len2=0;
char s1[10000];
char s2[10000];
bool Judge(int n,int k)
{
int a = 0,b = 0;
for(int i = 0;i < n;i++)
{
if(height[i] < k)
{
if(a == 1 && b == 1) return 1;
a = b = 0;
}
if(sa[i] >= 0 && sa[i] < len1) a++;
if(sa[i] > len1 && sa[i] < n-1) b++;
}
return 0;
}
int main()
{
scanf("%s%s",s1,s2);
len1=strlen(s1);
len2=strlen(s2);
for(int i=0; i<len1; i++)
num[i]=s1[i]-'a'+1;
num[len1]=28;
for(int i=0; i<len2; i++)
num[i+len1+1]=s2[i]-'a'+1; da(num,len1+len2+2,30);
calHeight(num,len1+len2+2); int len=min(len1,len2);
int ans=-1;
for(int i=1; i<=len; i++)
{
if(Judge(len1+len2+2,i))
{
ans=i;
break;
}
}
cout<<ans<<endl;
return 0;
}
//20 5 19 20 19 5 20 19 5 19 28 20 5 5 16 20 5 19 0 0 0

CF(427D-Match &amp; Catch)后缀数组应用的更多相关文章

  1. CF 427D Match &amp; Catch 求最短唯一连续LCS

    题目来源:CF 427D Match & Catch 题意:给出2个字符串 求最短的连续的公共字符串 而且该字符串在原串中仅仅出现一次 思路:把2个字符串合并起来求height 后缀数组hei ...

  2. CF #244 D. Match & Catch 后缀数组

    题目链接:http://codeforces.com/problemset/problem/427/D 大意是寻找两个字符串中最短的公共子串,要求子串在两个串中都是唯一的. 造一个S#T的串,做后缀数 ...

  3. Codeforces 427D Match &amp; Catch(后缀自动机)

    [题目链接] http://codeforces.com/problemset/problem/427/D [题目大意] 给出一个两个字符串,求出最短且在两个字符串中唯一的公共子串. [题解] 以原字 ...

  4. codeforces 427D Match & Catch(后缀数组,字符串)

    题目 参考:http://blog.csdn.net/xiefubao/article/details/24934617 题意:给两个字符串,求一个最短的子串.使得这个子串在两个字符串中出现的次数都等 ...

  5. cf244D. Match &amp; Catch 字符串hash (模板)或 后缀数组。。。

    D. Match & Catch 能够用各种方法做.字符串hash.后缀数组,dp.拓展kmp,字典树.. . 字符串hash(模板) http://blog.csdn.net/gdujian ...

  6. CF 504E Misha and LCP on Tree(树链剖分+后缀数组)

    题目链接:http://codeforces.com/problemset/problem/504/E 题意:给出一棵树,每个结点上有一个字母.每个询问给出两个路径,问这两个路径的串的最长公共前缀. ...

  7. CF 504E Misha and LCP on Tree——后缀数组+树链剖分

    题目:http://codeforces.com/contest/504/problem/E 树链剖分,把重链都接起来,且把每条重链的另一种方向的也都接上,在这个 2*n 的序列上跑后缀数组. 对于询 ...

  8. CF 504 E —— Misha and LCP on Tree —— 树剖+后缀数组

    题目:http://codeforces.com/contest/504/problem/E 快速查询LCP,可以用后缀数组,但树上的字符串不是一个序列: 所以考虑转化成序列—— dfs 序! 普通的 ...

  9. Codeforces 427 D. Match &amp; Catch

    后缀数组.... 在两个串中唯一出现的最小公共子串 D. Match & Catch time limit per test 1 second memory limit per test 51 ...

随机推荐

  1. 灰度共生矩阵(GLCM) 及matlab代码实现

    原地址:http://blog.csdn.net/bookwormno1/article/details/7962466 这几天学习灰度共生矩阵,现记录如下: 讲灰度共生矩阵比较好的一份百度文库文档: ...

  2. js封装好的模仿qq消息弹窗代码

    在我们的日常开发中,或者生活中.常常须要用到弹出窗.这里我们就用js模拟一下qq消息一样的弹出窗. 直接贴代码: <!DOCTYPE html PUBLIC "-//W3C//DTD ...

  3. 创建并使用静态库(ar 命令)

     创建并使用静态库(ar 命令)            archive命令的功能是:创建或改动归档文件或者从归档文件里析取信息.能够简单的理解为一个打包工具,将成员文件依照一定的规则构建到.a文件里, ...

  4. svnkit添加节点

    package com.repositoryclient.svnoptions; import org.tmatesoft.svn.core.SVNException; import org.tmat ...

  5. Android利用Get、Post 获取网络数据

    首先是Get: 布局非常easy.就一个button,主要看一下MainActivity吧: package com.francis.httpget; import android.app.Activ ...

  6. Coreseek:indexer crashed不解之谜

    前两天浩哥让我再把Coreseek的索引再做一次,由于需求那边有点变化,要把索引的公司名字显示出来,就在配置文件中面加入了sql_field_string:字符串字段.. 这个属性特别好用,由于它不仅 ...

  7. MYSQL正在使用select发现现场记录方法,包括一个逗号分隔的字符串

    首先,我们创建一个逗号分隔字符串. CREATE TABLE test(id int(6) NOT NULL AUTO_INCREMENT,PRIMARY KEY (id),pname VARCHAR ...

  8. Oracle历史记录

    请问如何查询ORACLE的历史操作记录!!!!!------解决方案-------------------- 有一个专门存储操作的数据库表..select t.SQL_TEXT, t.FIRST_LO ...

  9. Java整型数组的最大长度到底有多长?

    Java整型数组的最大长度到底有多长? 今天上网查了一下,各种说法都有,这个问题似乎总困扰我们Java初学者,无奈,只好自己试了一下,以下是我的测试代码,如果有错误,还望不吝赐教! 使用eclipse ...

  10. 在html中禁用自己主动完毕

    输入框输入内容时总是显示历史输入历史记录,现禁用的方法是加入一个属性: <input type="text name="txt_xm" autocomplete=& ...