题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5008

题目:


给出字符串s,找出字符串中字典序第k小的子串第一次出现的位置

解题思路:


height数组中,排名第i的后缀对子串的贡献(不包含重复的子串):该后缀中的所有长度大于height[i]的前缀。而且这样排出来的子串正好是有序的,字典序从小到大。

二分查找字典序第k小的子串所在的后缀排名rank1,向下找出最远的rank2,使得【rank1,rank2】区间的LCP>=字典序第k小的子串的长度。因为rank1对应的后缀是第一次出现字典序第k小的子串,所以只需要向下查找即可。

ac代码:


#include <bits/stdc++.h>
using namespace std;
const int maxn = 100020;
typedef long long ll;
//不能声明ws,保留字
int sa[maxn], wv[maxn], wss[maxn], wa[maxn], wb[maxn], r[maxn];
char s[maxn];
ll sum[maxn];
bool cmp(int *r, int a, int b, int l)
{return r[a] == r[b] && r[a + l] == r[b + l];
}
//O(nlogn)读入下标从0开始
void get_sa(int *r, int *sa, int n, int m)
{int *x=wa, *y=wb;int p =0, i, j;for(i = 0; i < m; i++) wss[i] = 0;for(i = 0; i < n; i++) wss[ x[i]=r[i] ]++;for(i = 1; i <= m; i++) wss[i] += wss[i - 1];for(i = n - 1; i >= 0; i--) sa[--wss[x[i]]] = i;for(j = 1, p = 1; p < n; j *= 2, m = p){//对第二关键字排序for(p = 0, i = n - j; i < n; i++) // [n-j,n)没有内容y[p++] = i;for(i = 0; i < n; i++)if(sa[i] >= j) y[p++] = sa[i] - j;//对第一关键字排序for(i = 0; i < n; i++) wv[i] = x[y[i]]; //排名为i的第二关键字对应的第一关键字的排名,x此时相当于rankk,y相当于第二关键字的safor(i = 0; i < m; i++) wss[i] = 0;for(i = 0; i < n; i++) wss[wv[i]]++;for(i = 1; i <= m; i++) wss[i] += wss[i - 1];for(i = n - 1; i >= 0; i--) sa[--wss[wv[i]]] = y[i];//相同的字符串排名相同swap(x,y);for(i = 1, p = 1, x[sa[0]] = 0; i < n; i++)x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1 : p++;}
}
//O(n)
int rankk[maxn], height[maxn];
void get_height(int n)
{int k = 0;for(int i = 1; i <= n; i++) rankk[sa[i]] = i;for(int i = 0; i < n; i++){k ? k-- : 0;//根据性质height[rank[i]] ≥ (height[rank[i-1]] -1)int j = sa[rankk[i] - 1];//上一名的开始下标while(r[i + k] == r[j + k]) k++;height[rankk[i]] = k;}
}
int  idd[maxn][30], hd[maxn][30]; //2<<20长度
void rmq_init(int n, int a[], int d[][30])
{for(int i = 1; i <= n; i++) d[i][0] = a[i];for(int j = 1; (1 << j) <= n; j++){for(int i = 1; i + (1 << j) -1 <= n; i++)d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);}
}
int rmq(int l ,int r, int d[][30])
{int k = int(log((double)(r - l +1)) / log(2.0));return min(d[l][k], d[r - (1 << k) +1][k]);
}
int binary_search(int L, int R, int len)
{int ans = L - 1;while(L <= R){int mid = (L + R) >> 1;if(rmq(L, mid, hd) < len) R = mid - 1;else{ans = mid;L = mid + 1;}}return ans;
}
int main()
{//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);while(~scanf("%s", s)){int q;int len = strlen(s);for(int i = 0; i < len; i++)r[i] = (int)s[i];r[len] = 0;get_sa(r, sa, len+1, 255);get_height(len);for(int i = 1; i <= len; i++)sum[i] = sum[i-1] + (len - sa[i] - height[i]);rmq_init(len, height, hd);rmq_init(len, sa, idd);ll k, v, L = 0, R = 0 ;scanf("%d", &q);while(q--){scanf("%lld", &v);k = (L^R^v)+1;if(k > sum[len]){L = R = 0;printf("0 0\n");continue;}int id1 = lower_bound(sum+1, sum+1+len, k) - sum;int slen = height[id1] + k - sum[id1-1];int id2 = binary_search(id1+1, len, slen);int sid = rmq(id1, id2, idd);L = (ll)sid+1, R = (ll)sid + slen;printf("%lld %lld\n", L, R);}}return 0;
}

【HDU5008】Boring String Problem(后缀数组+二分查找+st表)相关推荐

  1. HDU - 5008 Boring String Problem(后缀数组+二分)

    题目链接:点击查看 题目大意:给出一个字符串,接下来给出 q 个询问,每次询问字符串中第 k 大的子串,要求输出该字串的左右端点,如果有多个答案,输出左端点最小的一个 题目分析:因为在求出后缀数组后, ...

  2. hdu 5008 Boring String Problem(后缀数组+rmq)

    题目链接:hdu 5008 Boring String Problem 题意: 给你一个字符串,有q个询问,每次询问该字符串所有的子串中字典序第k小的是哪个串,输出位置,如果有多个位置,输出最靠左的那 ...

  3. HDU 5008 Boring String Problem ( 后缀数组求本质不同第k大子串)

    Boring String Problem Zeronera题解 预处理sum数组记录不同字符串的个数,即sum[i] = n- sa[i] + 1 -height[i] + sum[i-1] (n为 ...

  4. bzoj3277 串 (后缀数组+二分答案+ST表)

    常见操作:先把所有串都连到一起,但中间加上一个特殊的符号(不能在原串中/出现过)作为分割 由于全部的子串就等于所有后缀的所有前缀,那我们对于每一个后缀,去求一个最长的前缀,来满足这个前缀在至少K个原串 ...

  5. HDU - 5008 Boring String Problem(后缀树求本质不同第k大子串)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串,再给出 mmm 次询问,每次询问需要输出本质不同第 kkk 小的子串的起止位置.如果有多个答案,输出起点最小的那个.强制在线. 题目分析 ...

  6. 洛谷P4094 [HEOI2016/TJOI2016]字符串【后缀数组+主席树+st表】

    时空限制 2000ms / 256MB 题目描述 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确 ...

  7. [SCOI2012]喵星球上的点名(后缀数组+莫队+ST表)

    传送门 这题是真的秀.一眼看下去感觉AC自动机很可做,第一个问比较好处理,dfs序即可搞定,可第二问有点抽象,目前对树形结构的知识点不足以支持我解决这个问题.所以舍弃AC自动机,用SA做. SA做法: ...

  8. 【NOI2016】优秀的拆分【后缀数组】【ST表】【关键点】【调和级数复杂度】【差分】

    传送门 题意:如果一个字符串可以拆分为AABB的形式,其中A和B是任意非空字符串,则我们这种拆分是优秀的.求给定串的所有子串的拆分方案数之和. N≤30000N \leq30000N≤30000 本来 ...

  9. java数组二分查找_java 13-1 数组高级二分查找

    查找: 1.基本查找:数组元素无序(从头找到尾) 2.二分查找(折半查找):数组元素有序 pS:数组的元素必须有顺序,从小到大或者从大到小.以下的分析是从小到大的数组 二分查找分析: A:先对数组进行 ...

  10. 有序数组二分查找最接近的值

    有序数组二分查找最接近的值 问题 思路 代码 循环的终止条件 如何改为求upper_bound 问题 给你一个有序数组,数组里面有正有负,有重复值,再给你扔一个target 数,求这个数组中最接近ta ...

最新文章

  1. ssm配置socket_ssm框架中集成websocket实现服务端主动向客户端发送消息
  2. BUCK/BOOST电路原理分析
  3. 批处理处理远程计算机,使用批处理文件在远程计算机上调整PowerShell窗口的大小...
  4. 程序代码移植和烧录需要注意什么_购买建站模板需要注意什么问题
  5. Java进阶:mysql的事务隔离级别面试题
  6. mysql 2008数据库配置文件_SQL Server 2008数据库的配置及连接
  7. 2019计算机科学与技术考研分数线,2019考研中国科学技术大学复试分数线已公布...
  8. Bootstrap采样方法的python实现
  9. 如何添加天锐绿盾屏幕水印
  10. BLE HID 协议-----蓝牙鼠标 代码流程分析
  11. JustAuth升级到v1.8.1版本,新增AuthState工具类,可自动生成state
  12. matlab为数据加表头,matlab xlswrite 表头
  13. 探寻埋藏在心底的梦想,社科院与杜兰大学金融管理硕士项目伴你同行
  14. 酷客多接受CCTV2财经频道专访
  15. 第39级台阶 小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!
  16. nRF24L01单芯片2.4GHz收发模块射频信道频率
  17. 利用python爬取甲骨文图片及其对应的汉字含义,共1062个甲骨文,百度云下载
  18. 计算机u盘设备无法启动不了,U盘不能识别,该设备无法启动。(代码10)
  19. 点线联合优化估计相机姿态(IROS 2022)
  20. 整数a和整数b间1的个数

热门文章

  1. 【狂神说Redis】2Redis入门 2-2Redis部署在Linux(Ubuntu)
  2. python qt 按钮实现拖放_[Python自学] PyQT5-控件拖拽、剪切板
  3. idea android模拟器无法启动,Flutter Hello world应用程序无法在Android模拟器x86_64上启动...
  4. mysql 系统变量_MySQL系统变量(查看和修改)
  5. 函数的基本知识点总结(附实例)
  6. web.config中文解释
  7. [NOI2016]优秀的拆分
  8. java上路系列之一
  9. Map 3D 2012定制和应用程序开发Webcast将于明天(6月23号)进行
  10. 从开发人员如何走向架构师