CF427D

SA的奇技淫巧,其实就是板子。

题意:

给定两个字符串,求最短的满足各只出现一次的连续公共字串

解析:

一般情况下,SA都是用来求最长公共前缀的,好像和这道题所求的最短公共子串没有任何关系。

但我们依然可以通过类比思路得出:

想一想为什么要寻找zz最大的元素?

因为如果小于最大值,那么最大值就会包含这个序列。

所以答案就是,一个元素,没有z值比这个元素大的,自然就是要选z的最大值

从上述思路,寻找如何让答案尽量小

z的次大值自然是不行的,但是发现次大值+1是满足条件的

一方面,它比最大值小,所以被唯一的最大值包含;另一方面,它比次大值大,所以仅被最大值包含

所以可证,次大值+1也是唯一的。

所以,按如上方法,对 $ S_1 $ 的每一个后缀求最大值和次大值,再用次大值更新答案

然后我们就能愉快的用SA解决这个问题了。

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring> using namespace std; #define LL long long
#define N 10010 string s1,s2,str;
int SA[N],rk[N],tp[N],cnt[N];
int len,tot,m,a[N],height[N]; void qsort() {
for(int i = 1 ; i <= m ; i++) cnt[i] = 0;
for(int i = 1 ; i <= tot; i++) cnt[rk[i]]++;
for(int i = 1 ; i <= m ; i++) cnt[i] += cnt[i - 1];
for(int i = tot ; i >= 1 ; i--) SA[cnt[rk[tp[i]]]--] = tp[i];
}
inline bool cmp(int *f,int x,int y,int w) {
return f[x] == f[y] && f[x + w] == f[y + w];
}
void build_SA() {
m = 127;
for(int i = 1 ; i <= tot ; i++) {
rk[i] = a[i];
tp[i] = i;
}
qsort();
for(int w = 1 , p = 0 ; p < tot ; w += w,m = p) {
p = 0;
for(int i = tot - w + 1 ; i <= tot ; i++) tp[++p] = i;
for(int i = 1 ; i <= tot ; i++) {
if(SA[i] > w) tp[++p] = SA[i] - w;
}
qsort();
swap(rk,tp);
rk[SA[1]] = p = 1;
for(int i = 2 ; i <= tot ; i++)
rk[SA[i]] = cmp(tp,SA[i],SA[i - 1],w) ? p : ++p;
}
int j = 0, k = 0;
for(int i = 1 ; i <= tot ; height[rk[i++]] = k) {
for(k = k ? k - 1 : k, j = SA[rk[i] - 1] ; a[i + k] == a[j + k] ; k++);
}
}
inline bool check(int k,int div) {
int cnt1 = 0,cnt2 = 0;
for(int i = 1 ; i <= tot ; i++) {
if(height[i] < k) {
if(cnt1 == 1 && cnt2 == 1) return true;
cnt1 = cnt2 = 0;
if(SA[i] <= div) cnt1++;
else if(SA[i] >= div) cnt2++;
continue;
}
if(SA[i] <= div) cnt1++;
else if(SA[i] >= div) cnt2++;
}
return cnt1 == 1 && cnt2 == 1;
} int main() {
cin>>s1>>s2;
len = s1.length();
str = s1 + '#' + s2;//加入'#'表示两个字符串的分界点。
tot = len + s2.length() + 1;
for(int i = 1 ; i <= tot ; i++) a[i] = str[i - 1];
build_SA();
int ans = -1;
for(int i = 1 ; i <= len ; i++) {
if(check(i,len)) {
ans = i;
break;
}
}
printf("%d \n",ans);
//system("pause");
return 0;
}

CF427D的更多相关文章

随机推荐

  1. 3-MySQL DBA笔记-开发基础

    第二部分 开发篇 本篇首先讲述数据库开发的一些基础知识,如关系数据模型.常用的SQL语法.范式.索引.事务等,然后介绍编程开发将会涉及的数据库的一些技巧,最后结合生产实际,提供一份开发规范供大家参考. ...

  2. sublime 配置大全

    最近玩 python ,一般用的编译器是 pycharm ,功能强大,但是苦于启动速度遂准备换坑,瞄上了 sublime .这里记录一下 sublime 的设置以及坑爹项,需要注意的是我用的是 sub ...

  3. 史上最全Java集合中List,Set以及Map等集合体系详解

    一.概述 List , Set, Map都是接口,前两个继承至collection接口,Map为独立接口 Set下有HashSet,LinkedHashSet,TreeSet List下有ArrayL ...

  4. Pattern Recognition and Machine Learning-01-Preface

    Preface Pattern recognition has its origins in engineering, whereas machine learning grew out of com ...

  5. CDH5.16.1的agent启动报错:ERROR Error, CM server guid updated, expected d9bcadb4-f983-41b8-a667-66760f47bc91, received a67f5efa-8473-4f6a-94d6-231d1f432ef0

    1 详细错误 0/Oct/2019 14:56:13 +0000] 28577 MainThread agent ERROR Error, CM server guid updated, expect ...

  6. linecache:高效的读取文本文件

    介绍  可以很方便的读取文件 读取特定行 import linecache ''' 我们常用的序列的索引是从0开始的,但是linecache模块读取的文件行号是从1开始的 ''' # 表示读取C:\p ...

  7. sudo身份切换

    sudo更改身份: 我们知道,使用 su 命令可以让普通用户切换到 root 身份去执行某些特权命令,但存在一些问题,比如说:仅仅为了一个特权操作就直接赋予普通用户控制系统的完整权限: 当多人使用同一 ...

  8. 如何避免重复安装AppiumSetting、Unlock以及Android ime

    老版本Appium(如1.4.16),找到如下路径(根据自己的安装路径找) C:\Program Files (x86)\Appium\node_modules\appium\lib\devices\ ...

  9. All-in-One Office,不容错过的办公插件

      WPS Office是由金山自主研发的一款办公软件套装,具备办公软件最常用的文字.表格.演示等多种功能. 这款国产办公软件不仅免费,而且具有内存小.海量模板.兼容性强.操作更加符合中国人使用习惯等 ...

  10. FFmpeg学习笔记之安装

    本随笔原文出自:一叶知秋0830链接:https://www.jianshu.com/p/ab469a2ffd28 1.下载FFmpeg 先进入要存放下载文件的目录,比如要放在/Users/qinji ...