POJ 2774 后缀数组

简介: POJ 2774 后缀数组

https://wenku.baidu.com/view/ed1be61e10a6f524ccbf85fd.html

题意:求两个串的最长公共子串

思路:在求出height数组之后,再把sa数组区分出来,只要其中一个sa[i] (s[i -1])数组是属于第一串,s[i - 1] (s[i])属于第二串,那么我们可以求得其最大值,之所以可以这样做,是因为sa数组已经对字符串按字典序排好序了

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn = 2e6 + 5;
char s1[maxn], s2[maxn], s[maxn];
int n, p1, p2, m, p;
int tx[maxn], sa[maxn], rak[maxn];
int height[maxn];
struct node {
  int x, y, id;
}a[maxn], b[maxn];
void rsort() {
  for (int i = 1; i <= m; i++) {
    tx[i] = 0;
  }
  for (int i = 1; i <= n; i++) {
    tx[a[i].y]++;
  }
  for (int i = 1; i <= m; i++) {
    tx[i] += tx[i - 1];
  }
  for (int i = 1; i <= n; i++) {
    b[tx[a[i].y]--] = a[i];
  }
  for (int i = 1; i <= m; i++) {
    tx[i] = 0;
  }
  for (int i = 1; i <= n; i++) {
    tx[b[i].x]++;
  }
  for (int i = 1; i <= m; i++) {
    tx[i] += tx[i - 1];
  }
  for (int i = n; i >= 1; i--) {
    a[tx[b[i].x]--] = b[i];
  }
}
void solve() {
  rsort();
  p = 0;
  for (int i = 1; i <= n; i++) {
    if (a[i].x == a[i - 1].x && a[i].y == a[i - 1].y) {
      rak[a[i].id] = p;
    } else {
      rak[a[i].id] = ++p;
    }
  }
  for (int i = 1; i <= n; i++) {
    a[i].x = rak[i];
    a[i].id = sa[rak[i]] = i;
    a[i].y = 0;
  }
  m = p;
}
void ssort() {
  m = 127;
  for (int i = 1; i <= n; i++) {
    a[i].x = a[i].y = s[i];
    a[i].id = i;
  }
  solve();
  for (int j = 1; j <= n; j <<= 1) {
    for (int i = 1; i + j <= n; i++) {
      a[i].y = a[i + j].x;
    }
    solve();
    if (p == n) {
      break;
    }
  }
} 
void get_Height() {
  int k = 0;
  for (int i = 1; i <= n; i++) {
    if (k) {
      k--;
    }
    int j = sa[rak[i] - 1];
    while (s[i + k] == s[j + k]) {
      k++;
    }
    height[rak[i]] = k;
  }
}
int main() {
  scanf("%s", s1 + 1);
  scanf("%s", s2 + 1);
  p1 = strlen(s1 + 1);
  p2 = strlen(s2 + 1);
  for (int i = 1; i <= p1; i++) {
    s[++n] = s1[i];
  }
  s[++n] = '#';
  for (int i = 1; i <= p2; i++) {
    s[++n] = s2[i];
  }
  ssort();
  get_Height();
  int ans = 0;
  for (int i = 2; i <= n; i++) {
    if (height[i] > ans) {
      if ((sa[i] < p1 && sa[i - 1] > p1) || (sa[i] > p1 && sa[i - 1] < p1)) {
        ans = height[i];
      }
    }
  }
  printf("%d\n", ans);
  return 0;
}
相关文章
|
Java C++
poj 1503 高精度加法
把输入的数加起来,输入0表示结束。 先看我Java代码,用BigINteger类很多东西都不需要考虑,比如前导0什么的,很方便。不过java效率低点,平均用时600ms,C/C++可以0ms过。
49 1
|
2月前
|
算法
lanqiao OJ 1366 spfa最短路
lanqiao OJ 1366 spfa最短路
26 0
|
7月前
Pseudoprime numbers(POJ-3641 快速幂)
Pseudoprime numbers(POJ-3641 快速幂)
|
7月前
|
自然语言处理 算法
KMP算法(A + B for you again—HDU - 1867 )
KMP算法(A + B for you again—HDU - 1867 )
poj 1990 MooFest 树状数组
题意就是有N头牛,每头牛都有一个坐标和声调值(x, v),两头牛之间通讯要花费的能量是他们的距离乘以最大的一个音调值,现在要任意两头牛之间都相互通讯一次,求总共需要花费多少能量?
52 0
AcWing 717. 简单斐波那契
AcWing 717. 简单斐波那契
106 0
AcWing 717. 简单斐波那契
POJ-3641,Pseudoprime numbers(快速幂)
POJ-3641,Pseudoprime numbers(快速幂)
|
人机交互
POJ-2524,Ubiquitous Religions(并查集模板题)
POJ-2524,Ubiquitous Religions(并查集模板题)