HDU - 5008 Boring String Problem (后缀数组+二分法+RMQ)
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
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)
the smallest l. If there is no l,r satisfied, output “0 0”. Note that s1...n is the whole string)
aaa
4
0
2
3
5
1 1
1 3
1 2
0 0
题意:求第k大的子串,输出左右端点,且左端点尽量小。
思路:首先。我们能够计算出不同的子串个数,这个在论文里有的。就是
n-sa[i]-height[i]。
然后我们就能够统计第i大的字符串有的子串个数,然后二分查找到第k个所在的第sa[i]后缀,接着我们能够先确定右端点的范围来RMQ查找sa[j]最小的那个。仅仅要是满足和sa[i]后缀的lcp的长度大于len,就代表也包括这个子串了,接着就是RMQ了,坑点就是l=mid的时候的多一个推断
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
//typedef long long ll;
typedef __int64 ll;
using namespace std;
const int maxn = 100010;
int sa[maxn];
int t1[maxn], t2[maxn], c[maxn];
int rank[maxn], height[maxn];
void build_sa(int s[], int n, int m) {
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 getHeight(int s[],int n) {
int i, j, k = 0;
for (i = 0; i <= n; i++)
rank[sa[i]] = i;
for (i = 0; i < n; i++) {
if (k) k--;
j = sa[rank[i]-1];
while (s[i+k] == s[j+k]) k++;
height[rank[i]] = k;
}
}
int dp[maxn][30];
char str[maxn];
int r[maxn], ind[maxn][30];
ll b[maxn];
void initRMQ(int n) {
int m = floor(log(n+0.0) / log(2.0));
for (int i = 1; i <= n; i++)
dp[i][0] = height[i];
for (int i = 1; i <= m; i++) {
for (int j = n; j; j--) {
dp[j][i] = dp[j][i-1];
if (j+(1<<(i-1)) <= n)
dp[j][i] = min(dp[j][i], dp[j+(1<<(i-1))][i-1]);
}
}
}
int lcp(int l, int r) {
int a = rank[l], b = rank[r];
if (a > b)
swap(a,b);
a++;
int m = floor(log(b-a+1.0) / log(2.0));
return min(dp[a][m], dp[b-(1<<m)+1][m]);
}
void init(int n) {
int m = floor(log(n+0.0) / log(2.0));
for (int i = 1; i <= n; i++)
ind[i][0] = sa[i];
for (int i = 1; i <= m; i++) {
for (int j = n; j; j--) {
ind[j][i] = ind[j][i-1];
if (j+(1<<(i-1)) <= n)
ind[j][i] = min(ind[j][i], ind[j+(1<<(i-1))][i-1]);
}
}
}
int rmq(int a, int b) {
int m = floor(log(b-a+1.0) / log(2.0));
return min(ind[a][m], ind[b-(1<<m)+1][m]);
}
int main() {
while (scanf("%s", str) != EOF) {
int n = strlen(str);
for (int i = 0; i <= n; i++)
r[i] = str[i];
build_sa(r, n+1, 128);
getHeight(r, n);
initRMQ(n);
init(n);
b[0] = 0;
for (int i = 1; i <= n; i++)
b[i] = b[i-1] + n - sa[i] - height[i];
int m;
scanf("%d", &m);
ll k;
int lastl = 0, lastr = 0;
while (m--) {
scanf("%I64d", &k);
k = (k ^ lastl ^ lastr) + 1;
if (k > b[n]) {
printf("0 0\n");
lastl = 0;
lastr = 0;
continue;
}
int id = lower_bound(b+1, b+1+n, k) - b;
k -= b[id-1];
int len = height[id] + k;
int ll = id;
int rr = id;
int L = id, R = n;
while (L <= R) {
int mid = (L + R) / 2;
if (sa[id] == sa[mid] || lcp(sa[id], sa[mid]) >= len) {
rr = mid;
L = mid + 1;
}
else R = mid - 1;
}
int ansl = rmq(ll, rr) + 1;
int ansr = ansl + len - 1;
printf("%d %d\n", ansl, ansr);
lastl = ansl;
lastr = ansr;
}
}
return 0;
}
版权声明:本文博客原创文章,博客,未经同意,不得转载。
HDU - 5008 Boring String Problem (后缀数组+二分法+RMQ)的更多相关文章
- HDU 5008 Boring String Problem(后缀数组+二分)
题目链接 思路 想到了,但是木写对啊....代码 各种bug,写的乱死了.... 输出最靠前的,比较折腾... #include <cstdio> #include <cstring ...
- HDU 5008 Boring String Problem
题意:给定一个串长度<=1e5,将其所有的不同的字串按照字典序排序,然后q个询问,每次询问字典序第k小的的起始坐标,并且起始坐标尽量小. 分析: 一开始看错题意,没有意识到是求不同的字串中第k小 ...
- HDU5008 Boring String Problem(后缀数组)
练习一下字符串,做一下这道题. 首先是关于一个字符串有多少不同子串的问题,串由小到大排起序来应该是按照sa[i]的顺序排出来的产生的. 好像abbacd,排序出来的后缀是这样的 1---abbacd ...
- HDOJ 5008 Boring String Problem
后缀数组+RMQ+二分 后缀数组二分确定第K不同子串的位置 , 二分LCP确定可选的区间范围 , RMQ求范围内最小的sa Boring String Problem Time Limit: 6000 ...
- HDU 3518 Boring counting(后缀数组,字符处理)
题目 参考自:http://blog.sina.com.cn/s/blog_64675f540100k9el.html 题目描述: 找出一个字符串中至少重复出现两次的字串的个数(重复出现时不能重叠). ...
- poj 1743 Musical Theme (后缀数组+二分法)
Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 16162 Accepted: 5577 De ...
- 【bzoj5073】[Lydsy1710月赛]小A的咒语 后缀数组+倍增RMQ+贪心+dp
题目描述 给出 $A$ 串和 $B$ 串,从 $A$ 串中选出至多 $x$ 个互不重合的段,使得它们按照原顺序拼接后能够得到 $B$ 串.求是否可行.多组数据. $T\le 10$ ,$|A|,|B| ...
- 【bzoj3879】SvT 后缀数组+倍增RMQ+单调栈
题目描述 (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示), ...
- HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given ...
随机推荐
- MIPS台OpenWrt在系统内的路由器Rust应用程序开发
笔者:Liigo(庄小莉) 迄今:2014年9一个月17日本 (9一个月29日更新,11一个月19日本再次更新.在最后可用更新) 原文链接:http://blog.csdn.net/liigo/art ...
- java计算器 图形用户界面 精简版
package com.rgy.entity; import java.awt.*; import java.awt.event.*; @SuppressWarnings("serial&q ...
- define a class for a linked list and write a method to delete the nth node.
1.问题 define a class for a linked list and write a method to delete the nth node. 2.算法 template <t ...
- OutputCache说明
当用户访问该页面,整个页面会server存储在内存中,因此,该页面缓存.当用户再次访问该页面,页面不会再次运行数据操作,页面首先检查server中是否存在缓存.假设缓存存在,则直接从缓存中获取页面信息 ...
- Redis 的性能
Redis 的性能幻想与残酷现实 2011 年,当初选择 Redis 作为主要的内存数据存储,主要吸引我的是它提供多样的基础数据结构可以很方便的实现业务需求.另一方面又比较担心它的性能是否足以支撑,毕 ...
- 最大公约数(Greatest Common Divisor)
两个数的最大公约数.一个典型的解决方案是欧几里德,叫欧几里德算法. 原理:(m,n)代表m和nGCD,和m>n.然后,(m,n)=(n,m%n)=.....直到余数为0. 码如下面: publi ...
- ASP.NET2.0自定义控件组件开发 第六章 深入讲解控件的属性
原文:ASP.NET2.0自定义控件组件开发 第六章 深入讲解控件的属性 深入讲解控件的属性持久化(一) 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开 ...
- redis基础的字符串类型
redis —— 第二篇 基础的字符串类型 我们都知道redis是采用C语言开发,那么在C语言中表示string都是采用char[]数组的,然后你可能会想,那还不简单,当我执行如下命令,肯定是直 接塞 ...
- 集成ejs和angular
我们也有一个系统angular用在应用中单页.正确angular做一些定制.集成seajs.不实用angular自己的模块管理. 只要angular也可单独使用在,一个较小的系统新开发,我不会用前js ...
- 13 于C#如何获得在IP住址
首先,需要加入一个命名空间 using System.Net.NetworkInformation; using System.Net.Sockets; 以下是具体代码 GetPrivateIP(); ...