HDU 5008 求第k小子串
本题要求第k小的distinct子串,可以根据height数组,二分出这个第k小子串所在后缀的位置信息。由于题目要求子串起始下标尽可能小。所以再在rank数组中,二分出与当前后缀LCP大于等于所求子串长度的范围。通过RMQ求出这个范围中最小的sa。
- #include <iostream>
- #include <vector>
- #include <algorithm>
- #include <string>
- #include <string.h>
- #include <stdio.h>
- #include <queue>
- #include <stack>
- #include <map>
- #include <set>
- #include <cmath>
- #include <ctime>
- #include <cassert>
- #include <sstream>
- using namespace std;
- const int N=;
- int MIN(int a,int b){return a<b?a:b;}
- int MAX(int a,int b){return a>b?a:b;}
- int val[N];
- struct RMQ {
- int dp[N][];
- int (*cmp) (int,int);
- void setMin(){cmp=MIN;}
- void setMax(){cmp=MAX;}
- void init(int n,int *val) {
- for (int i=; i<=n; i++)
- dp[i][]=val[i];
- for (int j=; (<<j)<=n; j++) {
- int k=<<(j-);
- for (int i=; i+k<=n; i++)
- dp[i][j]=cmp(dp[i][j-],dp[i+k][j-]);
- }
- }
- int query(int a,int b) {
- if (a>b) swap(a,b);
- int dis=b-a+;
- int k=log((double)dis)/log(2.0);
- return cmp(dp[a][k],dp[b-(<<k)+][k]);
- }
- }rmq;
- char s[N];
- struct SuffixArray {;
- int sa[N];
- int t1[N],t2[N],c[N];
- int rk[N],height[N];
- long long sum[N];
- inline int cmp(int *r,int a,int b,int l){
- return r[a]==r[b]&&r[a+l]==r[b+l];
- }
- void calcSA (char *s,int n,int m) {
- int i,j,p,*x=t1,*y=t2;
- for(i=;i<m;i++)c[i]=;
- for(i=;i<n;i++)c[x[i]=s[i]]++;
- for(i=;i<m;i++)c[i]+=c[i-];
- for(i=n-;i>=;i--)sa[--c[x[i]]]=i;
- for(j=;j<=n;j<<=){
- p=;
- for(i=n-j;i<n;i++)y[p++]=i;
- for(i=;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; // 排名从小到大,如果pos比j大,则suffix(sa[i]-j)的第二关键字为p
- for(i=;i<m;i++)c[i]=;
- for(i=;i<n;i++)c[x[y[i]]]++;
- for(i=;i<m;i++)c[i]+=c[i-];
- for(i=n-;i>=;i--)sa[--c[x[y[i]]]]=y[i]; // 根据第二关键字从大到小,确定新一轮sa
- swap(x,y);
- p=;x[sa[]]=;
- for(i=;i<n;i++)
- x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
- if(p>=n)break;
- m=p;
- }
- }
- void calcHeight(char *s,int n) {
- int i,j,k=;
- for(i=;i<=n;i++)rk[sa[i]]=i;
- for(i=;i<n;i++){
- if(k)k--; // h[i]>=h[i-1]-1
- j=sa[rk[i]-]; // suffix(j)排名在suffix(i)前一位
- while(s[i+k]==s[j+k])k++; // 暴力计算lcp
- height[rk[i]]=k;
- }
- sum[]=;
- for (int i=;i<=n;i++) sum[i]=sum[i-]+n-sa[i]-height[i];
- }
- int lcp(int a,int b,int len) {
- if (a==b) return len-a;
- int ra=rk[a],rb=rk[b];
- if (ra>rb) swap(ra,rb);
- return queryST(ra+,rb);
- }
- int st[N][];
- void initST(int n) {
- for (int i=;i<=n;i++)
- st[i][]=height[i];
- for (int j=;(<<j)<=n;j++) {
- int k=<<(j-);
- for (int i=; i+k<=n; i++)
- st[i][j]=min(st[i][j-],st[i+k][j-]);
- }
- }
- int queryST(int a,int b) {
- if (a>b) swap(a,b);
- int dis=b-a+;
- int k=log((double)dis)/log(2.0);
- return min(st[a][k],st[b-(<<k)+][k]);
- }
- void solve(int &l,int &r,long long k,int n) {
- if (k<||k>sum[n]) {
- l=;r=;
- return;
- }
- int t=lower_bound(sum,sum+n+,k)-sum;
- assert(t>=&&t<=n);
- long long now=sum[t-];
- int need=k-now;
- l=sa[t],r=sa[t]+height[t]+need-;
- int len=r-l+;
- int le=t,ri=n,ret=l;
- while (le<=ri) {
- int mid=(le+ri)/;
- if (lcp(sa[mid],l,n)>=len) {
- le=mid+;
- ret=mid;
- } else ri=mid-;
- }
- l=rmq.query(t,ret);
- l++;
- r=l+len-;
- }
- }suf;
- int main () {
- while (scanf("%s",s)!=EOF) {
- int n=strlen(s);
- suf.calcSA(s,n+,);
- suf.calcHeight(s,n);
- suf.initST(n);
- rmq.setMin();
- rmq.init(n,suf.sa);
- int Q;
- scanf("%d",&Q);
- int l=,r=; //int cnt=0;
- while (Q--) {
- long long k;
- scanf("%I64d",&k);
- k^=(l^r);
- k++;
- //k=++cnt;
- suf.solve(l,r,k,n);
- printf("%d %d\n",l,r);
- }
- }
- return ;
- }
HDU 5008 求第k小子串的更多相关文章
- SPOJ SUBLEX 求第k小子串
题目大意: 对于一个给定字符串,找到其所有不同的子串中排第k小的子串 先构建后缀自动机,然后我们可以将整个后缀自动机看做是一个DAG图,那么我们先进行拓扑排序得到 *b[N] 对于每个节点记录一个sc ...
- BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串
http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...
- hdu 4217 Data Structure? 树状数组求第K小
Data Structure? Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- 「BZOJ3998」[TJOI2015] 弦论(第K小子串)
https://www.lydsy.com/JudgeOnline/problem.php?id=3998 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input ...
- [TJOI2015]弦论(第k小子串)
题意: 对于一个给定的长度为n的字符串,求出它的第k小子串. 有参数t,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个. 题解: 首先,因为t的原因,后缀数组较难实现, ...
- 树状数组求第k小的元素
int find_kth(int k) { int ans = 0,cnt = 0; for (int i = 20;i >= 0;i--) //这里的20适当的取值,与MAX_VAL有关,一般 ...
- 算法导论学习之线性时间求第k小元素+堆思想求前k大元素
对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思 ...
- 求第k小的数
题目链接:第k个数 题意:求n个数中第k小的数 题解: //由快速排序算法演变而来的快速选择算法 #include<iostream> using namespace std; const ...
- *HDU2852 树状数组(求第K小的数)
KiKi's K-Number Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
随机推荐
- C#知识整理笔记
这里简单介绍了一些常用的属性,以及一些术语的解释和举例说明,不太全面,希望读者多多补充. 1.重载:函数名相同,参数的个数或参数类型不同; public void MyDog(string s); p ...
- KoaHub.JS用于Node.js的可移植Unix shell命令程序代码
shelljs Portable Unix shell commands for Node.js ShellJS - Unix shell commands for Node.js Shell ...
- NSPredicate 查询/搜索
IOS NSPredicate 查询.搜索 简述:Cocoa框架中的NSPredicate用于查询,原理和用法都类似于SQL中的where,作用相当于数据库的过滤取. 最常用到的函数 + (NSP ...
- Effective Modern C++ Item 37:确保std::thread在销毁时是unjoinable的
下面这段代码,如果调用func,按照C++的标准,程序会被终止(std::terminate) void func() { std::thread t([] { std::chrono::micros ...
- 实现在easyui中的datagrid,点击某一列的列头弹出combobox下拉框
easyUI datagrid在列头加下拉框,实现对列内容的筛选. 代码: onLoadSuccess: function (data) {//Fires when data is loaded s ...
- CentOS7搭建Confluence Wiki
前言 在艾佳生活实习时,有三款团队协作系统特别喜欢:Wiki.Jira和Jenkins.对于Jenkins的搭建,之前<自动部署工具Jenkins>有过记录.这次,搭建一个Wiki,作为知 ...
- download 下载文件 IE兼容性处理
根据CANIUSE(http://caniuse.com/#search=download)download兼容性如下图所示: 如上图所示,IE浏览器是不支持的. 1.测试代码: <!docty ...
- 000 Python之禅
The Zen of Python, by Tim Peters Beautiful is better than ugly.Explicit is better than implicit.Simp ...
- GitHub中最强大的iOS Notifications和AlertView框架,没有之一!
FFToast是一个非常强大的iOS message notifications和AlertView扩展.它可以很容易实现从屏幕顶部.屏幕底部和屏幕中间弹出一个通知.你可以很容易的自定义弹出的View ...
- iOS开发之UITableView及cell重用
1.UITanleview有的两种风格 一种是Plain,一种是Grouped,可以从这里设置风格: 他们样式分别如下: Plain: Grouped: 2.tableView展示数据的过程: (1) ...