练习一下字符串,做一下这道题。

首先是关于一个字符串有多少不同子串的问题,串由小到大排起序来应该是按照sa[i]的顺序排出来的产生的。

好像abbacd,排序出来的后缀是这样的

1---abbacd     第一个串产生的6个前缀都是新的子串

2---acd          第二个串除了和上一个串的前缀1 3-1=2 产生了2个子串

3---bacd        4-0=4

4---bbacd      5-1=4

5---cd           2-0=0

6---d            1-0=0

所以所有不同的前缀应该是(len-sa[i])-lcp[i-1]的和,即串长减去与上一个串的最长公共前缀,然后求和。

所以我们可以预处理出dp[i]表示sa[i]的后缀所产生的新串的个数,然后对dp[i]求一次前缀和,那么每次询问第k大的串的时候就可以直接lower_bound,找出串的左端和右端。但是这个(l,r)不一定是最小的,最小的可能是在sa[i+1]..sa[i+2]...里产生,所以我们首先要二分出合法的sa边界,即sa[i]....sa[j]里都可以产生的这个串,然后sa[i]...sa[j]的最小值即是我们要求的。写二分总是要跪要跪的- -0

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <string>
#include <numeric>
#include <cassert>
using namespace std; #define maxn 120000
#define ll long long struct SuffixArray
{
int n;
int m[2][maxn];
int sa[maxn];
char s[maxn]; void indexSort(int sa[], int ord[], int id[], int nId){
static int cnt[maxn];
memset(cnt, 0, sizeof(0)*nId);
for (int i = 0; i < n; i++){
cnt[id[i]]++;
}
partial_sum(cnt, cnt + nId, cnt);
for (int i = n - 1; i >= 0; i--){
sa[--cnt[id[ord[i]]]] = ord[i];
}
} int *id, *oId; void init(){
n = strlen(s) + 1;
static int w[maxn];
for (int i = 0; i <= n; i++) w[i] = s[i];
sort(w, w + n);
int nId = unique(w, w + n) - w;
id = m[0], oId = m[1];
for (int i = 0; i < n; i++){
id[i] = lower_bound(w, w + nId, s[i]) - w;
}
static int ord[maxn];
for (int i = 0; i < n; i++){
ord[i] = i;
}
indexSort(sa, ord, id, nId);
for (int k = 1; k <= n&&nId < n; k <<= 1){
int cur = 0;
for (int i = n - k; i < n; i++){
ord[cur++] = i;
}
for (int i = 0; i < n; i++){
if (sa[i] >= k) ord[cur++] = sa[i] - k;
}
indexSort(sa, ord, id, nId);
cur = 0;
swap(oId, id);
for (int i = 0; i < n; i++){
int c = sa[i], p = i ? sa[i - 1] : 0;
id[c] = (i == 0 || oId[c] != oId[p] || oId[c + k] != oId[p + k]) ? cur++ : cur - 1;
}
nId = cur;
}
} // lcp relevant
int rk[maxn], lcp[maxn];
void getlcp(){
for (int i = 0; i < n; i++) rk[sa[i]] = i;
int h = 0;
lcp[0] = 0;
for (int i = 0; i < n; i++){
int j = sa[rk[i] - 1];
for (h ? h-- : 0; i + h < n&&j + h < n&&s[i + h] == s[j + h]; h++);
lcp[rk[i] - 1] = h;
}
} // lcp query relevant
int d[maxn + 50][25];
int mi[maxn+50][25]; void getrmq(){
for (int i = 0; i < n; i++) d[i][0] = lcp[i];
for (int j = 1; (1 << j) < n; j++){
for (int i = 0; (i + (1 << j) - 1) < n; i++){
d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
}
}
for(int i=0;i<n;i++) mi[i][0]=sa[i];
for (int j = 1; (1 << j) < n; j++){
for (int i = 0; (i + (1 << j) - 1) < n; i++){
mi[i][j] = min(mi[i][j - 1], mi[i + (1 << (j - 1))][j - 1]);
}
}
} int rmq_query3(int l,int r){
if(l==r) return mi[l][0];
int k=0;int len=r-l+1;
while((1<<(k+1))<len) ++k;
return min(mi[l][k], mi[r - (1 << k) + 1][k]);
} int rmq_query(int l, int r){
if(l==r) return n-1-sa[l];
if (l > r) swap(l, r); r -= 1;
int k = 0; int len = r - l + 1;
while ((1 << (k + 1)) < len) k++;
return min(d[l][k], d[r - (1 << k) + 1][k]);
} int rmq_query2(int l, int r){
l = rk[l], r = rk[r];
if (l > r) swap(l, r); r -= 1;
int k = 0; int len = r - l + 1;
while ((1 << (k + 1)) < len) k++;
return min(d[l][k], d[r - (1 << k) + 1][k]);
}
}sa; int nQ;
ll dp[maxn];
int n;
int main()
{
while(~scanf("%s",sa.s)){
sa.init();
sa.getlcp();
sa.getrmq();
n=sa.n-1;
dp[0]=0;
for(int i=1;i<=n;++i){
dp[i]=n-sa.sa[i]-sa.lcp[i-1];
dp[i]+=dp[i-1];
}
ll ansl=0,ansr=0;
ll ki;
scanf("%d",&nQ);
while(nQ--){
scanf("%I64d",&ki);
ki=(ki^ansl^ansr)+1;
if(ki>dp[n]){
ansl=ansr=0;
printf("%d %d\n",ansl,ansr);
continue;
}
int tl,tr;
int id=lower_bound(dp,dp+n+1,ki)-dp;
tl=sa.sa[id];
tr=tl+sa.lcp[id-1]+ki-dp[id-1]-1;
int len=tr-tl+1;
int lf=id,rf=n;
while(lf<rf){
int mid=(lf+rf+1)>>1;
if(sa.rmq_query(id,mid) >= len) lf=mid;
else rf=mid-1;
}
ansl=sa.rmq_query3(id,lf)+1;
ansr=ansl+len-1;
printf("%I64d %I64d\n",ansl,ansr);
}
}
return 0;
}

HDU5008 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. HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)

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

  4. HDOJ 5008 Boring String Problem

    后缀数组+RMQ+二分 后缀数组二分确定第K不同子串的位置 , 二分LCP确定可选的区间范围 , RMQ求范围内最小的sa Boring String Problem Time Limit: 6000 ...

  5. 【HDU 5030】Rabbit's String (二分+后缀数组)

    Rabbit's String Problem Description Long long ago, there lived a lot of rabbits in the forest. One d ...

  6. HDU 6194 string string string(后缀数组+RMQ)

    string string string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  7. HDU 3518 Boring counting(后缀数组,字符处理)

    题目 参考自:http://blog.sina.com.cn/s/blog_64675f540100k9el.html 题目描述: 找出一个字符串中至少重复出现两次的字串的个数(重复出现时不能重叠). ...

  8. HDU 5008 Boring String Problem

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

  9. Gym - 102028H Can You Solve the Harder Problem? (后缀数组+RMQ+单调栈)

    题意:求一个序列中本质不同的连续子序列的最大值之和. 由于要求“本质不同”,所以后缀数组就派上用场了,可以从小到大枚举每个后缀,对于每个sa[i],从sa[i]+ht[i]开始枚举(ht[0]=0), ...

随机推荐

  1. 装黑苹果的那些事儿(以ThinkpadE540为例)

    苹果系统,有着比window更好的安全性和方便性,更重要的事,没有MAC系统环境,进行iOS开发,是很麻烦的,对新手来说,是很懊恼的一件事.但是白苹果像件奢侈品,吾等常人,很难有经济消费.如是黑苹果是 ...

  2. 【转】Winform下KeyDown,KeyPress,KeyUp事件的总结

    http://blog.csdn.net/xiashengwang/article/details/6777907

  3. 使用工厂bean和Utility Schema定义集合

    工厂bean是实现了beanFactory接口的bean,也可以继承AbstractFactoryBean,主要是用于在给定属性参数之后自动创建一个bean对象. 我们在使用基本集合标记定义集合时,不 ...

  4. Hadoop和大数据:60款顶级大数据开源工具

    一.Hadoop相关工具 1. Hadoop Apache的Hadoop项目已几乎与大数据划上了等号.它不断壮大起来,已成为一个完整的生态系统,众多开源工具面向高度扩展的分布式计算. 支持的操作系统: ...

  5. 从此不再惧怕URI编码:JavaScript及C# URI编码详解

    混乱的URI编码 JavaScript中编码有三种方法:escape.encodeURI.encodeURIComponent C#中编码主要方法:HttpUtility.UrlEncode.Serv ...

  6. Python实现PLA(感知机)

    Python实现PLA(感知机) 运行环境 Pyhton3 numpy(科学计算包) matplotlib(画图所需,不画图可不必) 计算过程 st=>start: 开始 e=>end o ...

  7. 无法找到脚本文件 C:/Windows/explorer.exe:574323188.vbs

    今天打开电脑后电脑有点反常,在启动时没有运行 “局域网” 保护的程序,而且还他是 “无法找到脚本文件”如下图: 发现这个东西后,第一反应,拔掉网线.因为很有可能是中病毒了,当时就出了一身冷汗,到底是怎 ...

  8. Xcode 7遇到 App Transport Security has blocked a cleartext HTTP 错误

    今天用Xcode 7 创建新项目用到 URL 发送请求时,报下面的错: “App Transport Security has blocked a cleartext HTTP (http://) r ...

  9. JAVA内部类(转)

    源出处:JAVA内部类 在java语言中,有一种类叫做内部类(inner class),也称为嵌入类(nested class),它是定义在其他类的内部.内部类作为其外部类的一个成员,与其他成员一样, ...

  10. Android -- View

    setContentView                                                                        只要你使用过Activity ...