CodeForces 427D Match & Catch 后缀数组
来源:互联网 发布:淘宝培训机构靠谱吗 编辑:程序博客网 时间:2024/05/17 04:13
题目:https://cn.vjudge.net/problem/CodeForces-427D
题意:给出两个字符串,求最小公共子串长度,使这个子串仅在两个串均出现一次。
思路:将这两个字符串拼成一个串,中间用一个没出现过的字符隔开(我用的空格),对合成的串求后缀数组,这样两个数组的公共子串所在的后缀在sa中应该是相邻的。通过观察,只有当这两个sa中相邻的后缀sa[i]和sa[i-1]左右的后缀都不含这个子串时,才能保证子串在两个串都只出现一次。
具体来说就是
(1)后缀sa[i]和sa[i-1]分别属于两个字符串
(2)height[i-1] < height[i] && height[i+1] < height[i]
(3)这个最小公共子串长度就是max(height[i-1], height[i+1]) + 1
整体扫过一遍height数组统计最小值即可,没有满足的情况时输出-1
代码:c++
#include <cstdio>#include <iostream>#include <cstring>#include <string>#include <algorithm>#include <cmath>using namespace std;const int maxn = 20000;const int INF = 2147483647;char s[maxn];int sa[maxn], t[maxn], t2[maxn], c[maxn];int n;//字符串s的下标从1到n,且s[0]必须为空字符//构造字符串s的后缀数组。每个字符ASCII值必须在0~m-1范围内void build_sa(int m, int n){ n++; int *x = t; int *y = t2; //基数排序 for (int i = 0; i < m; i++) { c[i] = 0; } for (int i = 0; i < n; i++) { x[i] = s[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[i]]] = i; } for (int k = 1; k <= n; k <<= 1) { int p = 0; //直接利用sa排序第二关键字 for (int i = n - k; i < n; i++) { y[p++] = i; } for (int i = 0; i < n; i++) { if (sa[i] >= k) { y[p++] = sa[i] - k; } } //基数排序第一关键字 for (int i = 0; i < m; i++) { c[i] = 0; } for (int i = 0; i < n; i++) { c[x[y[i]]]++; } for (int i = 0; i < m; i++) { c[i] += c[i - 1]; } for (int i = n - 1; i >= 0; i--) { sa[--c[x[y[i]]]] = y[i]; } //根据sa和y数组计算新的x数组 swap(x, y); p = 1; x[sa[0]] = 0; for (int i = 1; i < n; i++) { if (y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k]) { x[sa[i]] = p - 1; } else { x[sa[i]] = p++; } } //以后即使继续倍增,sa也不会改变 if (p >= n) { break; } m = p;//下次基数排序的最大值 }}int ranks[maxn], height[maxn];//ranks[i]是后缀i的排名//height[i]是后缀i和后缀i-1的最长公共前缀长度void getHeight(int n){ n++; int k = 0; for (int i = 0; i < n; i++) { ranks[sa[i]] = i; } for (int i = 0; i < n; i++) { if (ranks[i] == 0) { height[0] = 0; continue; } // 第一个后缀的 LCP 为 0。 if (k) { k--; // 从 k - 1 开始推 } int j = sa[ranks[i] - 1]; while (s[i + k] == s[j + k] && i + k < n && j + k < n) { k++; } height[ranks[i]] = k; }}int belong[maxn];//0 - 空字符,1 - 第一个串,2 - 第二个串void init(){ scanf("%s", s + 1); n = strlen(s + 1); for (int i = 1; i <= n; i++) { belong[i] = 1; } s[++n] = ' '; scanf("%s", &s[n + 1]); int st2 = n + 1; n += strlen(&s[n + 1]); for (int i = st2; i <= n; i++) { belong[i] = 2; } build_sa(200, n); getHeight(n);}int solve(){ int minn = INF; for (int i = 1; i <= n; i++) { if (belong[sa[i - 1]] + belong[sa[i]] == 3) { if (height[i - 1] < height[i] && height[i + 1] < height[i]) { minn = min(minn, max(height[i - 1], height[i + 1]) + 1); } } } return minn == INF ? -1 : minn;}int main(){ init(); printf("%d\n", solve()); return 0;}
阅读全文
0 0
- codeforces 427 D Match & Catch ( 后缀数组 )
- CodeForces 427D Match & Catch 后缀数组
- Codeforces 427D Match & Catch 后缀自动机 或 后缀数组
- CodeForces 427 D.Match & Catch(后缀数组)
- Codeforces 427D Match & Catch 后缀自动机
- cf 427D Match & Catch 后缀数组
- Codeforces 427D Match & Catch(后缀自动机)
- CF(427D-Match & Catch)后缀数组应用
- Codeforces 427 D. Match & Catch
- CodeForces 427D-Match & Catch
- CodeForces 427D-Match & Catch
- CodeForces 427D Match & Catch
- CF #244 (Div. 2) D Match & Catch (后缀数组 仅出现一次最短公共子串)
- cf244D. Match & Catch 字符串hash (模板)或 后缀数组。。。
- Codeforces Round #244 (Div. 2) D. Match & Catch
- Codeforces round 244(div.2) D match&catch【字符串hash】
- CF 427D Match & Catch 求最短唯一连续LCS
- codeforces 432D D . Prefixes and Suffixes(后缀数组)
- jquery 获取多选框的值
- 【Deep Learning】Faster R-CNN
- js获取被点击的元素以及子元素
- Linux的chattr与lsattr命令详解
- flask-sqlalchemy 数据基本操作
- CodeForces 427D Match & Catch 后缀数组
- Adroid音视频录制(1)——Surface录制
- PyTorch torch.bmm 实例
- 《iPhone X ARKit Face Tracking》
- 昨夜西风凋碧树
- 迎接双十二,EasyRecovery提前开抢买起来
- 创建glance镜像报错HTTP403
- 152. Maximum Product Subarray (最大乘积子数列)
- readyState与focus