题目链接:点击查看

题目大意:给出一个字符串,接下来给出 q 个询问,每次询问字符串中第 k 大的子串,要求输出该字串的左右端点,如果有多个答案,输出左端点最小的一个

题目分析:因为在求出后缀数组后,sa数组已经保证了升序,且每个后缀中的前缀也按照升序排列,所以我们可以构造一个前缀和,因为每一个后缀贡献的不重复的子串个数为 n - sa[ i ] - height[ i ],这样就能二分找到第k大的子串第一次出现的位置了,为什么说是第一次出现的位置呢?因为在此之后,可能会有与当前子串重复的子串,且在原字符串中更靠左的位置,为了找出最左边的位置,我们需要枚举所有可能,所谓所有可能,就是从当前位置开始,往后寻找所有sa数组与当前的sa数组的前缀包含了当前子串的位置,具体实现看代码吧

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;char str[N];int sa[N]; //SA数组,表示将S的n个后缀从小到大排序后把排好序的
//的后缀的开头位置顺次放入SA中
int t1[N],t2[N],c[N];int rk[N],height[N],len;int s[N];LL sum[N];void build_sa(int s[],int n,int m)//n为添加0后的总长
{int i,j,p,*x=t1,*y=t2;for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[i]=s[i]]++;for(i=1;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;for(j=1;j<=n;j<<=1) {p=0;for(i=n-j;i<n;i++) y[p++]=i;for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[y[i]]]++;for(i=1;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];swap(x,y);p=1,x[sa[0]]=0;for(i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;if(p>=n) break;m=p;}
}void get_height(int s[],int n)//n为添加0后的总长
{int i,j,k=0;for(i=0;i<=n;i++)rk[sa[i]]=i;for(i=0;i<n;i++) {if(k) k--;j=sa[rk[i]-1];while(s[i+k]==s[j+k]) k++;height[rk[i]]=k;}
}void solve(int base=128)
{build_sa(s,len+1,base);get_height(s,len);
}int main()
{
//  freopen("input.txt","r",stdin);
//  ios::sync_with_stdio(false);while(scanf("%s",str)!=EOF){len=strlen(str);for(int i=0;i<len;i++)s[i]=str[i]-'a'+1;s[len]=0;solve(30);for(int i=1;i<=len;i++)sum[i]=sum[i-1]+len-sa[i]-height[i];int m;scanf("%d",&m);int l=0,r=0;while(m--){LL k;scanf("%lld",&k);k=(l^r^k)+1;if(k>sum[len]){printf("%d %d\n",l=0,r=0);continue;}int pos=lower_bound(sum+1,sum+1+len,k)-sum;//二分找到包含第一次出现第k大的子串的后缀l=sa[pos];//这里的l是第一次出现的第k大子串的左端点r=len-(sum[pos]-k+1);//右端点int lenn=r-l+1;//长度while(pos+1<=len&&height[pos+1]>=lenn)//枚举从当前位置开始往后的所有可能sa数组{pos++;l=min(l,sa[pos]);//维护最小值r=min(r,sa[pos]+lenn-1);}printf("%d %d\n",++l,++r);}}return 0;
}

HDU - 5008 Boring String Problem(后缀数组+二分)相关推荐

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

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

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

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

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

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

  4. HDU - 5030 Rabbit's String(后缀数组+二分)

    题目链接:点击查看 题目大意:给出一个字符串,现在要求将其分为不大于k个连续的子串,对于每个子串求出字典序最大的子串,现在要求所有子串的最大子串的最大值最小,输出这个最大子串 题目分析:最大值最小,标 ...

  5. HDU 6194 String String String (后缀数组+线段树, 2017 ACM/ICPC Asia Regional Shenyang Online)

    Problem 求字符串 S 中严格出现 k 次的子串个数 k≥1k\ge 1 |S|≤105|S|\le 10^5 ∑|S|≤2×106\sum |S| \le 2\times 10^6 Idea ...

  6. 2021ICPC(沈阳) - String Problem(后缀树+贪心)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串 sss,对于每个前缀来说,求出字典序最大的子串. 题目分析:看到子串的字典序,感觉能用后缀树来做,参考了一下大佬的赛上代码: 香港中文大 ...

  7. HDU - 4552 怪盗基德的挑战书(后缀数组+RMQ/KMP+dp)

    题目链接:点击查看 题目大意:给出一个字符串,统计每个前缀在字符串中出现的次数之和 题目分析:可以直接先用后缀数组跑出来height,再用RMQ跑出来任意两个后缀的height,我们可以将题意转换为求 ...

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

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

  9. SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)

    [题目链接] http://www.spoj.pl/problems/PHRASES/ [题目大意] 求在每个字符串中出现至少两次的最长的子串 [题解] 注意到这么几个关键点:最长,至少两次,每个字符 ...

最新文章

  1. Mac电脑如何显示隐藏文件
  2. linux ping 端口_教你排除linux中网络故障问题
  3. linux与windows间共享文件夹 FileZilla树莓派文件传输
  4. 垃圾分类智能化-垃圾分类机器人
  5. Javascript高级程序设计3笔记 - 对象
  6. MySQL数据库常用的操作命令(二)
  7. 平面设计师友好的免抠PNG图片素材
  8. SIFT特征检测算子和sift = cv2.xfeatures2d.SIFT_create出错的解决办法
  9. radon变换(c++、OpenCV实现)
  10. 软件工程--团队作业2
  11. 读Google MapReduce后有感
  12. 阿里云实践训练营第七天——Class6 NAS快速搭建个人网盘
  13. wifi网络工作原理
  14. Unity动态(在代码中)更改Shader的相关属性(如颜色、Smoothness、材质……)
  15. 每日一题 No.4 男女搭配干活不累
  16. java判定成绩等级_Java编程判断一组学生成绩等级
  17. Connectify+Wireshark捕获手机APP的数据包
  18. 通达OA二次开发手册
  19. 应用在hiapk安卓市场分类排行榜中不显示的原因
  20. 雨课堂知识点总结(十三)

热门文章

  1. vue检测对象值_Vue 不能检测到对象属性的添加或删除,注意!!!
  2. MySQL分组查询—添加筛选的总结
  3. Spring5的集成兼容
  4. 实现Redis用户会话 - 2
  5. Swagger2介绍
  6. Spring源码分析前篇
  7. 为排序使用索引OrderBy优化
  8. 实例工厂配置bean
  9. AdminLTE基本使用介绍
  10. 登陆状态下加入购物车