HDU 5008 Boring String Problem
题意:给定一个串长度<=1e5,将其所有的不同的字串按照字典序排序,然后q个询问,每次询问字典序第k小的的起始坐标,并且起始坐标尽量小。
分析:
一开始看错题意,没有意识到是求不同的字串中第k小的,果断不知道怎么做,感觉如果题目改成这样,似乎还有点难度,至少对我来说。
好了,这个题目是考虑不同的字串,首先后缀数组处理,也就是讲后缀按照字典序排序,对于每个后缀开始的字串,如h[i],容易知道i和i-1的后缀的LCP长度为h[i]那么i中除开前h[i]个字串,之后的字串在i-1之前都是没有出现过的,而且字典序要比之前的大,这样的字串数目时len-sa[i]-h[i],那么对于每个i用val[i]表示,sum[i]表示前i项的val值之和,对于第k小的字串,找到一个sum[i]>k,然后判断一下sum[i-1]是不是==k,不是的话说明第k小的字串一定在后缀i的字串中出现过,并算出长度L。然后再确定其在整个字符串中出现的最左位置,L>h[i]显然成立,所以L只能在i之后的后缀的字串中出现,找到一个范围i~r,使得之间的h值>=L,然后RMQ求出最小的sa值,也就是字串出现的最左位置。
话说暴力查找最左位置,竟然也能水过,而且速度还有快,测试数据里面肯定没有10000个a,每次询问第1小的字串这组数据。
考虑相同的字串,询问第k小的怎么做?
代码:
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#define inf 0x0f0f0f0f
#define pb push_back
#define bug(x) printf("line %d: >>>>>>>>>>>>>>>\n", (x));
#define in freopen("F:\\code\\data\\data.txt", "r", stdin);
#define out freopen("F:\\code\\data\\data_out.txt", "w", stdout); #define SZ(x) ((int)x.size())
#define lson rt<<1, l, m
#define rson rt<<1|1, m+1, r
#define fi first
#define se second
using namespace std;
typedef long long LL;
const int maxn = (int)1e5 + ;
int s[maxn], sa[maxn], t[maxn], t2[maxn], rk[maxn], h[maxn], c[maxn];
int n, m;
LL lans, rans;
LL sum[maxn], val[maxn]; void buildSa(int m)
{
int *x = t, *y = t2;
for(int i = ; i < m; i++) c[i] = ;
for(int i = ; i < n; i++) c[x[i]=s[i]]++; for(int i = ; i < m; i++) c[i] += c[i-];
for(int i = n-; i >= ; i--) sa[--c[x[i]]] = i; for(int k = ; k <= n; k <<= )
{
int p = ;
for(int i = n-k; i < n; i++) y[p++] = i;
for(int i = ; i < n; i++) if(sa[i] >= k) y[p++] = sa[i]-k; for(int i = ; i < m; i++) c[i] = ;
for(int i = ; i < n; i++) c[x[i]]++;//
for(int i = ; i < m; i++) c[i] += c[i-];
for(int i = n-; i >= ; i--) sa[--c[x[y[i]]]] = y[i]; p = ;
swap(x, y);
x[sa[]] = ; for(int i = ; i < n; i++)
x[sa[i]] = y[sa[i]] == y[sa[i-]] && y[sa[i]+k] == y[sa[i-]+k] ? p- : p++;
m = p;
if(p >= n)
break;
}
}
void getHeight()
{
int k = , j;
h[] = ;
for(int i = ; i < n; i++) rk[sa[i]] = i;
for(int i = ; i < n; i++)
{
if(k) k--;
if(rk[i] == )
continue;
j = sa[rk[i]-];
while(s[i+k] == s[j+k])
k++;
h[rk[i]] = k;
}
}
int dp[maxn][], mx[maxn][];
void rmqInit(int a[][], int h[])
{
for(int i = ; i < n; i++) a[i][] = i;
for(int k = ; (<<k) <= n; k++)
for(int i = ; i + (<<k) <= n; i++)
a[i][k] = h[a[i][k-]] < h[a[i+(<<(k-))][k-]] ? a[i][k-] : a[i+(<<(k-))][k-];
}
int RMQ(int l, int r, int a[][], int h[])
{
if(l > r) swap(l, r);
int k = ;
while((<<(k+)) < r-l+) k++;
return h[a[l][k]] < h[a[r-(<<k)+][k]] ? a[l][k] : a[r-(<<k)+][k];
}
char str[maxn];
int check(int l, int r)
{
return h[RMQ(l, r, dp, h)];
}
void solve(LL k)
{
if(k > sum[n-])
{
lans = rans = ;
return;
}
int kk = upper_bound(sum+, sum+n, k)-sum;
if(sum[kk-] == k)
kk--;
k -= sum[kk-]; int len = h[kk]+k;
int x = sa[kk];
if(kk+ < n && h[kk+] >= len)
{
int l = kk+, r = n;
while(r-l > )
{
int mid = (l+r)>>;
if(check(mid, kk+) >= len)
l = mid;
else r = mid;
}
x = min(x, sa[RMQ(kk+, l, mx, sa)]);
}
lans = x+, rans = x+len;
}
int main()
{ while(scanf("%s", str) == )
{
n = ;
for(int i = ; str[i]; i++)
s[n++] = str[i]-'a'+;
s[n++] = ;
buildSa();
getHeight();
rmqInit(dp, h);
rmqInit(mx, sa);
// bug(1)
int q;
lans = rans = ;
for(int i = ; i < n; i++)
{
val[i] = n--sa[i]-h[i];
sum[i] = sum[i-] + val[i];
}
for(int t = scanf("%d", &q); t <= q; t++)
{
LL v;
scanf("%I64d", &v);
LL k = (lans^rans^v)+;
solve(k);
printf("%I64d %I64d\n", lans, rans);
}
}
return ;
}
HDU 5008 Boring String Problem的更多相关文章
- 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 ...
- HDU 5008 Boring String Problem(后缀数组+二分)
题目链接 思路 想到了,但是木写对啊....代码 各种bug,写的乱死了.... 输出最靠前的,比较折腾... #include <cstdio> #include <cstring ...
- HDOJ 5008 Boring String Problem
后缀数组+RMQ+二分 后缀数组二分确定第K不同子串的位置 , 二分LCP确定可选的区间范围 , RMQ求范围内最小的sa Boring String Problem Time Limit: 6000 ...
- HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given ...
- HDU5008 Boring String Problem(后缀数组)
练习一下字符串,做一下这道题. 首先是关于一个字符串有多少不同子串的问题,串由小到大排起序来应该是按照sa[i]的顺序排出来的产生的. 好像abbacd,排序出来的后缀是这样的 1---abbacd ...
- hdu 5008 查找字典序第k小的子串
Boring String Problem Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Ot ...
- hdu String Problem(最小表示法入门题)
hdu 3374 String Problem 最小表示法 view code#include <iostream> #include <cstdio> #include &l ...
- HDU 3374 String Problem(KMP+最大/最小表示)
String Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- HDU 3374 String Problem (KMP+最大最小表示)
HDU 3374 String Problem (KMP+最大最小表示) String Problem Time Limit: 2000/1000 MS (Java/Others) Memory ...
随机推荐
- 《编写高质量代码》CSS部分总结
如何组织CSS 三层结构:base+common+page 分层目的:减少代码量:便于多人开发和维护 1.base层 最底层,一般设置文件为只读,与具体的UI无关,提供: reset功能.因为浏览器对 ...
- php上传文件大小限制
和你的配置文件有关.改一下PHP配置文件php.ini给你总结下相关配置,自己去改吧 1.php.ini:upload_max_filesize 所上传的文件的最大大小.默认值2M. 2.php.in ...
- ubuntu中下运行asp.net程序
首先在ubuntu下面是不能直接运行VISUAL STUTIO的,必须借助mono开发工具和xsp4.0.那我们就来看一下在ubuntu的电脑中怎么安装这两个工具. 首先安装mono,打开终端,输入a ...
- Ext.Net 布局
Ext.Net 布局 Panel布局类有10种:容器布局,自适应布局,折叠布局,卡片式布局,锚点布局,绝对位置布局,表单布局,列布局,表格布局,边框布局 1,Ext.layout.Cont ...
- C# 预处理指令
导读 1.什么是预处理 2.预处理的好处 3.C#中的常见预处理指令 4.总结 什么是预处理 在计算机科学中,预处理通常是指利用某一程序(通常是预处理器)对某一格式的源码(如.cs C ...
- OC4_NSString操作
// // main.m // OC4_NSString操作 // // Created by zhangxueming on 15/6/10. // Copyright (c) 2015年 zhan ...
- Python快速入门学习笔记(一)
本篇文章适合有其他高级语言基础的人群阅读 使用的Python版本为python2.7 使用的编辑器为Sublime Text3 世界始于Hello World: print 'Hello world' ...
- 在windows下装2个mysql数据库的办法
如下 记录下以免找不到 http://blog.chinaunix.net/uid-77311-id-3450734.html 然后接下来是 1045的解决方案 可以在随便中找
- JS中undefined和null的区别
在写JS脚本的时候,经常会碰到“为空”的判断,其中主要有null和undefined的判断.这两个为空判断的主要区别是: 1) null是JS的关键字,是语法特性.undefined是全局对象的属性, ...
- ubuntu12.10可用更新源
ubutnu12.10自带的更新源已经失效,国内各大服务器的更新源,无论是网易.搜狐还是教育网的因此也失效了.附件是ubuntu12.10目前的可用更新源. 将地址中的“us.archive”换成“o ...