1304 字符串的相似度 后缀数组

简介: 1304 字符串的相似度 后缀数组

我们定义2个字符串的相似度等于两个串的相同前缀的长度。例如 “abc” 同 “abd” 的相似度为2,“aaa” 同 “aaab” 的相似度为3。

给出一个字符串S,计算S同他所有后缀的相似度之和。例如:S = “ababaa”,所有后缀为:


ababaa 6

babaa 0

abaa 3

baa 0

aa 1

a 1


S同所有后缀的相似度的和 = 6 + 0 + 3 + 0 + 1 + 1 = 11


输入

输入一个字符串S(1 <= L <= 1000000),L为字符串S的长度,且S由a-z的小写字母组成。

输出

输出S同所有后缀的相似度的和。

输入样例

ababaa

输出样例

11


后缀数组模板题,倍增算法O(nlogn)复杂度的过不去,需要DC3算法O(n)复杂度才能卡过去(正解是exKMP算法)但是我不会


倍增算法

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
char s[maxn];
int height[maxn], sa[maxn], tx[maxn], rak[maxn];
struct node {
  int x, y, id;
}a[maxn], b[maxn];
int n, m, p;
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 ssort() {
  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) {
      ++p;
    }
    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 solve() {
  m = 127;
  for (int i = 1; i <= n; i++) {
    a[i].x = a[i].y = s[i];
    a[i].id = i;
  }
  ssort();
  for (int j = 1; j <= n; j <<= 1) {
    for (int i = 1; i + j <= n; i++) {
      a[i].y = a[i + j].x;
    }
    ssort();
    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 (i + k <= n && j + k <= n && s[i + k] == s[j + k]) {
      k++;
    }
    height[rak[i]] = k;
  }
}
int main() {
  scanf("%s", s + 1);
  n = strlen(s + 1);
  solve(); get_Height();
  long long ans = 0;
  int mm = 1e9;
  for (int i = rak[1] + 1; i <= n; i++) {
    mm = min(mm, height[i]);
    ans += mm;
  }
  mm = 1e9;
  for (int i = rak[1]; i >= 1; i--) {
    mm = min(mm, height[i]);
    ans += mm;
  }
  cout << ans + n << endl;
  return 0;
}
相关文章
「题解」字符串中的所有单词进行倒排
题目要求 1、构成单词的字符只有26个大写或小写英文字母; 2、非构成单词的字符均视为单词间隔符; 3、要求倒排后的单词间隔符以一个空格表示;如果原字符串中相邻单词间有多个间隔符时,倒排转换后也只允许出现一个空格间隔符; 4、每个单词最长20个字母;
|
9月前
|
存储 编译器 C语言
Day2 排序子序列、倒置字符串
Day2 排序子序列、倒置字符串
66 0
|
9月前
|
机器学习/深度学习 算法 JavaScript
【动态规划】【回文】【字符串】1278分割回文串 III
【动态规划】【回文】【字符串】1278分割回文串 III
|
机器学习/深度学习 算法 索引
【字符串】最长回文子串 ( 蛮力算法 )
【字符串】最长回文子串 ( 蛮力算法 )
108 0
【字符串】最长回文子串 ( 蛮力算法 )
LeetCode 1422. 分割字符串的最大得分
给你一个由若干 0 和 1 组成的字符串 s ,请你计算并返回将该字符串分割成两个 非空 子字符串(即 左 子字符串和 右 子字符串)所能获得的最大得分。
253 0
|
机器学习/深度学习 算法 索引
【字符串】字符串查找 ( 蛮力算法 )
【字符串】字符串查找 ( 蛮力算法 )
167 0
【字符串】字符串查找 ( 蛮力算法 )
|
算法 Java 索引
【算法】给定一个字符串 s 和一些长度相同的单词 words,串联所有单词的子串。要不要来试一试?
给定一个字符串 s 和一些长度相同的单词 words串联所有单词的子串
164 0
【算法】给定一个字符串 s 和一些长度相同的单词 words,串联所有单词的子串。要不要来试一试?

热门文章

最新文章