码迷,mamicode.com
首页 > 其他好文 > 详细

LCS&LCS2 SAM SPOJ

时间:2018-11-22 00:31:01      阅读:251      评论:0      收藏:0      [点我收藏+]

标签:math   cstring   code   sub   des   solution   不同   har   set   

LCS - Longest Common Substring

Description

给两个长度\(\le 250000\)的小写字母串, 求最长公共子串.

Solution

子串就是SAM了. 对其中一个建出SAM, 另一个在上面跑, 如果可以转移, 就直接转移, 长度加一, 否则跳父亲到可以转移, 自然是取\(max_{\alpha}\)了.

如果都不行就回到根.

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cctype>

using namespace std;

const int maxn = 700005;

int ans;
char s1[maxn], s2[maxn];

struct SuffixAutoMation
{
  int tr[maxn][26], fa[maxn], mx[maxn];
  int lst, cnt;
  SuffixAutoMation() {
    lst = cnt = 1;
  }
  void Insert(int c)  {
    int p = lst, np = ++cnt;
    lst = np; mx[np] = mx[p] + 1;
    for (; p && !tr[p][c]; p = fa[p]) tr[p][c] = np;
    if (!p) fa[np] = 1;
    else {
      int q = tr[p][c];
      if (mx[p] + 1 == mx[q]) fa[np] = q;
      else {
        int nq = ++cnt;
        mx[nq] = mx[p] + 1;
        for (int i = 0; i < 26; ++i) tr[nq][i] = tr[q][i];
        fa[nq] = fa[q]; fa[q] = fa[np] = nq;
        for (; tr[p][c] == q; p = fa[p]) tr[p][c] = nq;
      }
    }
    //siz[np] = 1;
  }
  void Build(int n) {
    for (int i = 1; i <= n; ++i)
      Insert(s1[i] - 'a');
  }
  void Solve(int n) {
    int pos = 1, len = 0;
    for (int i = 1; i <= n; ++i) {
      int ch = s2[i] - 'a';
      if (tr[pos][ch]) len++, pos = tr[pos][ch];
      else {
        for (; pos && !tr[pos][ch]; ) pos = fa[pos];
        if (pos) len = mx[pos] + 1, pos = tr[pos][ch];
        else pos = 1, len = 0;
      }
      ans = max(ans, len);
    }
  }
}SAM;

int main() {
  scanf("%s%s", s1 + 1, s2 + 1);
  int l1 = strlen(s1 + 1), l2 = strlen(s2 + 1);
  SAM.Build(l1);
  SAM.Solve(l2);
  printf("%d\n", ans);
  return 0;
}

LCS2 - Longest Common Substring

Description

还是小写字符串\((\le 100000)\), 不过增加到了\(10\)个.

Solution

建一个SAM, 其他的分别在上面跑, 求出\(ans_{\alpha}\{2, 3, 4, \ldots,n\}\), 和\(max_{\alpha}\)取个min.

注意实现细节.

由于跑了很多串, 可能出现匹配位置不同的情况, 注意parent树节点的儿子的答案可以拿来取max. 用\(max\)的拓扑性就好了.

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cctype>

using namespace std;

const int maxn = 3e+5 + 5;

int n, ans;
int a[maxn], b[maxn];
char s[maxn];

struct SuffixAutoMation
{
  int tr[maxn][26], mx[maxn], sz[maxn], fa[maxn];
  int lst, cnt;
  int mxv[maxn], mnv[maxn];
  SuffixAutoMation() {
    lst = cnt = 1;
  }
  void Insert(int c) {
    int p = lst, np = ++cnt;
    lst = np; mx[np] = mx[p] + 1;
    for (; p && !tr[p][c]; p = fa[p]) tr[p][c] = np;
    if (!p) fa[np] = 1;
    else {
      int q = tr[p][c];
      if (mx[p] + 1 == mx[q]) fa[np] = q;
      else {
        int nq = ++cnt;
        mx[nq] = mx[p] + 1;
        for (int i = 0; i < 26; ++i) tr[nq][i] = tr[q][i];
        fa[nq] = fa[q]; fa[q] = fa[np] = nq;
        for (; tr[p][c] == q; p = fa[p]) tr[p][c] = nq;
      }
    }
    sz[np] = 1;
  }
  void RadixSort() {
    memset(b, 0, sizeof b);
    for (int i = 1; i <= cnt; ++i) b[mx[i]]++;
    for (int i = 1; i <= cnt; ++i) b[i] += b[i - 1];
    for (int i = 1; i <= cnt; ++i) a[b[mx[i]]--] = i;
  }
  void Build(int n) {
    for (int i = 1; i <= n; ++i) Insert(s[i] - 'a');
    memset(mnv, 0x3f, sizeof mnv);
  }
  void Work(int n) {
    int p = 1, len = 0;
    //memset(mxv, 0, sizeof mxv);
    for (int i = 1; i <= n; ++i)  {
      int ch = s[i] - 'a';
      if (tr[p][ch]) p = tr[p][ch], len++, mxv[p] = max(mxv[p], len);
      else {
        for (; p && !tr[p][ch]; ) p = fa[p];
        if (p) len = mx[p] + 1, p = tr[p][ch], mxv[p] = max(mxv[p], len);
        else p = 1, len = 0;
      }
    }
    for (int i = cnt; i; --i) {
      int x = a[i], f = fa[x];
      mxv[f] = max(mxv[f], min(mxv[x], mx[f]));
      mnv[x] = min(mnv[x], mxv[x]);
      mxv[x] = 0;
    }
  }
  void CheckAns() {
    for (int i = 1; i <= cnt; ++i) ans = max(ans, mnv[i]);
  }
}SAM;

int main() {
  scanf("%s", s + 1);
  //memset(mnv, 0x3f, sizeof mnv);
  int l = strlen(s + 1);
  SAM.Build(l);
  SAM.RadixSort();
  while (scanf("%s", s + 1) != EOF) {
    
    l = strlen(s + 1);
    //if (!l) break;
    ++n;
    SAM.Work(l);
  }
  SAM.CheckAns();
  printf("%d\n", ans);
  return 0;
}

LCS&LCS2 SAM SPOJ

标签:math   cstring   code   sub   des   solution   不同   har   set   

原文地址:https://www.cnblogs.com/nishikino-curtis/p/9998144.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!