后缀数组+RMQ+二分

后缀数组二分确定第K不同子串的位置 , 二分LCP确定可选的区间范围 , RMQ求范围内最小的sa

Boring String Problem

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 661    Accepted Submission(s): 183

Problem Description
In this problem, you are given a string s and q queries.



For each query, you should answer that when all distinct substrings of string s were sorted lexicographically, which one is the k-th smallest. 



A substring si...j of the string s = a1a2 ...an(1 ≤ i ≤ j ≤ n) is the string aiai+1 ...aj. Two substrings sx...y and sz...w are cosidered to be distinct if sx...y ≠
Sz...w
 
Input
The input consists of multiple test cases.Please process till EOF. 



Each test case begins with a line containing a string s(|s| ≤ 105) with only lowercase letters.



Next line contains a postive integer q(1 ≤ q ≤ 105), the number of questions.



q queries are given in the next q lines. Every line contains an integer v. You should calculate the k by k = (l⊕r⊕v)+1(l, r is the output of previous question, at the beginning of each case l = r = 0, 0 < k < 263, “⊕” denotes exclusive or)
 
Output
For each test case, output consists of q lines, the i-th line contains two integers l, r which is the answer to the i-th query. (The answer l,r satisfies that sl...r is the k-th smallest and if there are several l,r available, ouput l,r which with
the smallest l. If there is no l,r satisfied, output “0 0”. Note that s1...n is the whole string)
 
Sample Input
aaa
4
0
2
3
5
 
Sample Output
1 1
1 3
1 2
0 0
 
Source
 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath> using namespace std; typedef long long int LL; const int maxn=110100;
const int INF=0x3f3f3f3f; int sa[maxn],rank[maxn],rank2[maxn],h[maxn],c[maxn],
*x,*y,ans[maxn];
char str[maxn]; bool cmp(int* r,int a,int b,int l,int n)
{
if(r[a]==r[b]&&a+l<n&&b+l<n&&r[a+l]==r[b+l])
return true;
return false;
} void radix_sort(int n,int sz)
{
for(int i=0;i<sz;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[y[i]]]++;
for(int i=1;i<sz;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
} void get_sa(char c[],int n,int sz=128)
{
x=rank,y=rank2;
for(int i=0;i<n;i++) x[i]=c[i],y[i]=i;
radix_sort(n,sz);
for(int len=1;len<n;len<<=1)
{
int yid=0;
for(int i=n-len;i<n;i++) y[yid++]=i;
for(int i=0;i<n;i++) if(sa[i]>=len) y[yid++]=sa[i]-len; radix_sort(n,sz); swap(x,y);
x[sa[0]]=yid=0; for(int i=1;i<n;i++)
{
x[sa[i]]=cmp(y,sa[i],sa[i-1],len,n)?yid:++yid;
}
sz=yid+1;
if(sz>=n) break;
}
for(int i=0;i<n;i++) rank[i]=x[i];
} void get_h(char str[],int n)
{
int k=0; h[0]=0;
for(int i=0;i<n;i++)
{
if(rank[i]==0) continue;
k=max(k-1,0);
int j=sa[rank[i]-1];
while(i+k<n&&j+k<n&&str[i+k]==str[j+k]) k++;
h[rank[i]]=k;
}
} LL Range[maxn]; int bin(LL x,int n)
{
int ans=-1;
int low=0,high=n-1,mid;
while(low<=high)
{
mid=(low+high)/2;
if(Range[mid]<x)
{
ans=mid;
low=mid+1;
}
else
{
high=mid-1;
}
}
return ans;
} int lcp[maxn][20],mmm[maxn][20]; void RMQ_init(int n)
{
for(int i=0;i<n;i++)
{
lcp[i][0]=h[i];
mmm[i][0]=sa[i];
}
lcp[0][0]=0x3f3f3f3f;
int sz=floor(log(n*1.0)/log(2.0));
for(int i=1;(1<<i)<=n;i++)
{
for(int j=0;j+(1<<i)-1<n;j++)
{
lcp[j][i]=min(lcp[j][i-1],lcp[j+(1<<(i-1))][i-1]);
mmm[j][i]=min(mmm[j][i-1],mmm[j+(1<<(i-1))][i-1]);
}
}
} int LCP(int l,int r,int n)
{
if(l==r) return n-sa[l];
l++;
if(l>r) swap(l,r);
int k=0;
while(1<<(k+1)<=r-l+1) k++;
return min(lcp[l][k],lcp[r-(1<<k)+1][k]);
} int MMM(int l,int r)
{
if(l>r) swap(l,r);
int k=0;
while(1<<(k+1)<=r-l+1) k++;
return min(mmm[l][k],mmm[r-(1<<k)+1][k]);
} int binID(int x,int n,int len)
{
int ans=x;
int low=x,high=n-1,mid;
while(low<=high)
{
mid=(low+high)/2;
if(LCP(x,mid,n)>=len)
{
ans=mid;
low=mid+1;
}
else high=mid-1;
}
return ans;
}
int main()
{
while(scanf("%s",str)!=EOF)
{
int n=strlen(str);
get_sa(str,n);
get_h(str,n);
RMQ_init(n);
for(int i=0;i<n;i++)
{
Range[i]=(n-sa[i])-h[i];
if(i-1>=0) Range[i]+=Range[i-1];
}
int q;
scanf("%d",&q);
int L=0,R=0;
LL V;
while(q--)
{
scanf("%I64d",&V);
LL K=(L^R^V)+1LL;
if(K>Range[n-1])
{
L=0;R=0;
printf("%d %d\n",L,R);
continue;
}
int id=bin(K,n);
LL jian=0;
if(id>=0) jian=Range[id];
LL res=K-jian; id++;
int len=h[id]+res;
int hid=binID(id,n,len);
int Left=MMM(id,hid);
printf("%d %d\n",Left+1,Left+len);
L=Left+1;R=Left+len;
}
}
return 0;
}

HDOJ 5008 Boring String Problem的更多相关文章

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

    Problem Description In this problem, you are given a string s and q queries. For each query, you sho ...

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

    题目链接 思路 想到了,但是木写对啊....代码 各种bug,写的乱死了.... 输出最靠前的,比较折腾... #include <cstdio> #include <cstring ...

  3. HDU 5008 Boring String Problem

    题意:给定一个串长度<=1e5,将其所有的不同的字串按照字典序排序,然后q个询问,每次询问字典序第k小的的起始坐标,并且起始坐标尽量小. 分析: 一开始看错题意,没有意识到是求不同的字串中第k小 ...

  4. HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given ...

  5. HDU5008 Boring String Problem(后缀数组)

    练习一下字符串,做一下这道题. 首先是关于一个字符串有多少不同子串的问题,串由小到大排起序来应该是按照sa[i]的顺序排出来的产生的. 好像abbacd,排序出来的后缀是这样的 1---abbacd ...

  6. HDU 3374 String Problem(KMP+最大/最小表示)

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  7. hdu3374 String Problem【最小表示法】【exKMP】

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  8. hdu3374 String Problem

    地址:http://acm.hdu.edu.cn/showproblem.php?pid=3374 题目: String Problem Time Limit: 2000/1000 MS (Java/ ...

  9. HDU3374 String Problem —— 最小最大表示法 + 循环节

    题目链接:https://vjudge.net/problem/HDU-3374 String Problem Time Limit: 2000/1000 MS (Java/Others)    Me ...

随机推荐

  1. ssm框架下上传图片及其他信息

    先引入这两个包: <dependency> <groupId>commons-fileupload</groupId> <artifactId>comm ...

  2. IOS Sqlite用户界面增删改查案例

    1.案例简单介绍 对SQLite操作进行了简单的封装,将对数据表操作转变成对对象的操作,并通过UI界面完毕对用户表的增.删.改.查,执行界面例如以下图所看到的 a 2.项目project文件夹 Use ...

  3. js中callback执行

    <!DOCTYPE HTML> <html> <head> <meta charset="GBK" /> <title> ...

  4. 使用NFS共享硬盘

    1. 安装 sudo apt install nfs-kernel-server   2. 配置   sudo vi /etc/exports   /mnt/NewDisk *(rw,sync,no_ ...

  5. oracle-常见的执行计划(一)

    一.表访问方式 CBO基础概念中有讲到,访问表的方式有两种:全表扫描和ROWID扫描. 全表扫描的执行计划:TABLE ACCESS FULL ROWID扫描对应执行计划:TABLE ACCESS B ...

  6. Android TextView加下划线的几种方式

    如果是在资源文件里: <resources> <</u></string> <string name="app_name">M ...

  7. Android 使用retrofit时,怎样获取响应的头信息

    这个问题,我前段时间在项目中使用Retrofit遇到过,最后查到的解决办法有两种获取Response Headers的方法,第一种是直接在定义接口是让接口返回Retrofit的Response对象,在 ...

  8. 新疆大学(新大)OJ xju 1006: 比赛排名 第二类斯特林数+阶乘

    题目链接:http://acm.xju.edu.cn/JudgeOnline/problem.php?id=1006 第二类斯特林数: 第二类Stirling数实际上是集合的一个拆分,表示将n个不同的 ...

  9. dialog.setCancelable与setCanceledOnTouchOutside的区别

    dialog.setCancelable(false); dialog弹出后会点击屏幕或物理返回键,dialog不消失 dialog.setCanceledOnTouchOutside(false); ...

  10. Java文件(io)编程——文件字节流的使用

    案例1: 演示FileInputStream类的使用(用FileInputStream的对象把文件读入到内存) 首先要在E盘新建一个文本文件,命名为test.txt,输入若干字符 public cla ...