SPOJ SUBLEX Lexicographical Substring Search - 后缀数组

题目传送门

  传送门I

  传送门II

题目大意

  给定一个字符串,多次询问它的第$k$大本质不同的子串,输出它。

  考虑后缀Trie。依次考虑每个后缀新增的本质不同的子串个数,显然,它是$n - sa[i] - height[i]$。

  求出$height$数组后,求一求本质不同的子串个数的前缀和,可以对每个询问二分。

  这里可以直接离线,$O(n + m)$扫一扫就好了。

Code

  1 /**
  2  * SPOJ
  3  * Problem#SUBLEX
  4  * Accepted
  5  * Time: 30ms
  6  * Memory: 19456k
  7  */
  8 #include <bits/stdc++.h>
  9 using namespace std;
 10 typedef bool boolean;
 11
 12 typedef class Pair3 {
 13     public:
 14         int x, y, id;
 15 }Pair3;
 16
 17 typedef class Query {
 18     public:
 19         int k, s, t, id;
 20
 21         boolean operator < (Query b) const {
 22             return k < b.k;
 23         }
 24 }Query;
 25
 26 const int N = 1e5 + 5, M = 505;
 27
 28 int n, m;
 29 char str[N], bs[N];
 30 int rk[N << 1], sa[N], hei[N], cnt[N];
 31 Pair3 ps[N], buf[N];
 32 Query qs[M];
 33
 34 inline void init() {
 35     scanf("%s", str + 1);
 36     n = strlen(str + 1);
 37     scanf("%d", &m);
 38     for (int i = 1; i <= m; i++)
 39         scanf("%d", &qs[i].k), qs[i].id = i;
 40 }
 41
 42 inline void radix_sort(Pair3* x, Pair3* y) {
 43     int m = ((n > 256) ? (n) : (256));
 44     memset(cnt, 0, sizeof(int) * (m + 1));
 45     for (int i = 1; i <= n; i++)    cnt[x[i].y]++;
 46     for (int i = 1; i <= m; i++)    cnt[i] += cnt[i - 1];
 47     for (int i = 1; i <= n; i++)    y[cnt[x[i].y]--] = x[i];
 48     memset(cnt, 0, sizeof(int) *  (m + 1));
 49     for (int i = 1; i <= n; i++)    cnt[y[i].x]++;
 50     for (int i = 1; i <= m; i++)    cnt[i] += cnt[i - 1];
 51     for (int i = n; i; i--)    x[cnt[y[i].x]--] = y[i];
 52 }
 53
 54 inline void build_sa() {
 55     for (int i = 1; i <= n; i++)
 56         rk[i] = str[i];
 57     for (int k = 1, dif = 0; k <= n; k <<= 1, dif = 0) {
 58         for (int i = 1; i <= n; i++)
 59             ps[i].x = rk[i], ps[i].y = rk[i + k], ps[i].id = i;
 60         radix_sort(ps, buf);
 61         rk[ps[1].id] = ++dif;
 62         for (int i = 2; i <= n; i++)
 63             rk[ps[i].id] = (dif += (ps[i].x != ps[i - 1].x || ps[i].y != ps[i - 1].y));
 64         if (dif == n)
 65             break;
 66     }
 67     for (int i = 1; i <= n; i++)
 68         sa[rk[i]] = i;
 69 }
 70
 71 inline void get_height() {
 72     for (int i = 1, j, k = 0; i <= n; i++) {
 73         if (k)    k--;
 74         if (rk[i] > 1) {
 75             for (j = sa[rk[i] - 1]; i + k <= n && j + k <= n && str[i + k] == str[j + k]; k++);
 76             hei[rk[i]] = k;
 77         } else
 78             hei[1] = 0;
 79     }
 80 }
 81
 82 inline void solve() {
 83     build_sa();
 84     get_height();
 85 //    for (int i = 1; i <= n; i++)
 86 //        cerr << hei[i] << " ";
 87 //    cerr << endl;
 88     sort(qs + 1, qs + m + 1);
 89     long long cur = 0;
 90     for (int i = 1, nq = 1, delta; i <= n && nq <= m; i++) {
 91         delta = n - sa[i] + 1 - hei[i];
 92         if (cur + delta < qs[nq].k)
 93             cur += delta;
 94         else {
 95             qs[nq].s = sa[i], qs[nq].t = sa[i] + hei[i] + (qs[nq].k - cur);
 96             nq++, i--;
 97         }
 98     }
 99     for (int i = 1; i <= m; i++)
100         while (qs[i].id != i)
101             swap(qs[qs[i].id], qs[i]);
102     for (int i = 1; i <= m; i++) {
103         int len = qs[i].t - qs[i].s;
104         memcpy(bs, str + qs[i].s , len);
105         bs[len] = 0;
106         puts(bs);
107     }
108 }
109
110 int main() {
111     init();
112     solve();
113     return 0;
114 }

原文地址:https://www.cnblogs.com/yyf0309/p/8643872.html

时间: 2024-11-12 00:10:47

SPOJ SUBLEX Lexicographical Substring Search - 后缀数组的相关文章

SPOJ SUBLEX - Lexicographical Substring Search

SUBLEX - Lexicographical Substring Search no tags Little Daniel loves to play with strings! He always finds different ways to have fun with strings! Knowing that, his friend Kinan decided to test his skills so he gave him a string S and asked him Q q

SPOJ 7258 Lexicographical Substring Search(后缀自动机)

[题目链接] http://www.spoj.com/problems/SUBLEX/ [题目大意] 给出一个字符串,求其字典序排名第k的子串 [题解] 求出sam上每个节点被经过的次数,然后采用权值线段树上查找第k大数类似的方法, 每次确定查找范围,进入相应的子树,同时输出路径上的点即可. [代码] #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const

SPOJ SUBLEX 7258. Lexicographical Substring Search

看起来像是普通的SAM+dfs...但SPOJ太慢了......倒腾了一个晚上不是WA 就是RE ..... 最后换SA写了...... Lexicographical Substring Search Time Limit: 1000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu [Submit]   [Go Back]   [Status] Description Little Daniel loves to play wi

HDU 1403 Longest Common Substring(后缀数组,最长公共子串)

hdu题目 poj题目 参考了 罗穗骞的论文<后缀数组——处理字符串的有力工具> 题意:求两个序列的最长公共子串 思路:后缀数组经典题目之一(模版题) //后缀数组sa:将s的n个后缀从小到大排序后将 排序后的后缀的开头位置 顺次放入sa中,则sa[i]储存的是排第i大的后缀的开头位置.简单的记忆就是“排第几的是谁”. //名次数组rank:rank[i]保存的是suffix(i){后缀}在所有后缀中从小到大排列的名次.则 若 sa[i]=j,则 rank[j]=i.简单的记忆就是“你排第几”

POJ 3693 Maximum repetition substring (后缀数组)

题目大意: 求出字典序最小,重复次数最多,的子串. 思路分析: RMQ + height 数组可以求出任意两个后缀的lcp 我们枚举答案字符串的重复的长度. 如果这个字符串的长度为 l ,而且这个字符串出现过两次或两次以上 那么你会发现在原串中  str[0] str[l] str[2*l] ....肯定有相邻的两个被包含在重复的串中. 我们求出这两个相邻的后缀的lcp 我们上面仅仅说的是被包含在重复的串中,但并不一定就是以 str[0], str[l],str[2*l]....为起点的. 那我

Lexicographical Substring Search SPOJ - SUBLEX (后缀数组)

Lexicographical Substrings Search \[ Time Limit: 149 ms \quad Memory Limit: 1572864 kB \] 题意 给出一个字符串,求出这个字符串上字典序第 \(k\) 小的子串. 思路 对于给出的字符串,求出后缀数组,根据后缀数组的 \(height\) 数组,我们可以很容易得到一个字符的总子串个数是 \(\sum_{i=1}^{n} (n-sa[i]+1+height[i])\),利用这个式子,就可以求出第 \(k\) 小

Lexicographical Substring Search SPOJ - SUBLEX (后缀自动机)

Lexicographical Substrings Search \[ Time Limit: 149 ms \quad Memory Limit: 1572864 kB \] 题意 给出一个字符串,求出这个字符串上字典序第 \(k\) 小的子串. 思路 先对给出的字符串构建后缀自动机,因为后缀自动机上从根节点走到任意节点都是原串的一个子串,所以我们可以 \(dfs\) 求出节点 \(i\) 往后存在多少个子串. 对于查询第 \(k\) 小的子串时,在用一个 \(dfs\) 来求,对于当前节点

SPOJ 705 Distinct Substrings(后缀数组)

[题目链接] http://www.spoj.com/problems/SUBST1/ [题目大意] 给出一个串,求出不相同的子串的个数. [题解] 对原串做一遍后缀数组,按照后缀的名次进行遍历, 每个后缀对答案的贡献为n-sa[i]+1-h[i], 因为排名相邻的后缀一定是公共前缀最长的, 那么就可以有效地通过LCP去除重复计算的子串. [代码] #include <cstdio> #include <cstring> #include <algorithm> usi

HDU 1403 Longest Common Substring(后缀数组啊 求最长公共子串 模板题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403 Problem Description Given two strings, you have to tell the length of the Longest Common Substring of them. For example: str1 = banana str2 = cianaic So the Longest Common Substring is "ana", a