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扁平化博客学习总结(一)模块分析
一.模块分析 1.每开发一个项目之前,首先要对项目进行一个大致规划,它到底要做什么功能,它有什么具体需求. 2.所以需要进行模块化分析,把这些东西具象化,把一个问题模块化,对需求有一个宏观的了解. 3 ...
- linux gpg 使用笔记
http://linux.chinaunix.net/techdoc/system/2009/04/30/1109541.shtml 一.GnuPG的简介 我们在网上的发送的邮件是明文的,可以 ...
- 【JavaScript权威指南(第五版)】笔记之第二部分 客户端JavaScript 第13章~第23章
第十三章 Web浏览器中的javascript ① eg:下面两行代码实际上执行的是相同的功能 var answer = 42; window.answer = 42; ③每个window对象 ...
- Android之Http网络编程(四)
前面几篇博文简单的介绍了一些常见的Http的操作,这些操作几乎都是在新开的线程中进行的网络请求,并在日志中打印出获取到的网络数据.那么,问题来了!(呃~感觉下一句是蓝翔有木有?)如何在把获取到的网络数 ...
- SQL SERVER中的逻辑读,预读和物理读
sqlserver:数据存储方式:最小单位是页,每一页8k,sqlserver 对页的读取是具有原子性,也就是说,要么读取完整一页,要么完全不读取,不会有中间状态,而页之间的数据组织结构是B树 但是每 ...
- Aix命令大全
AIX服务器系统命令简介 在AIX操作系统上有很多的命令.这里介绍一些系统级的命令,它将有助于回答一些常见问题.大家以此做参考,并补充修改. 以下命令在AIX 5.1上测试通过. 正文 以下命令在AI ...
- html19-----视频,音乐的插入
视频格式 MP4 格式是一种新的即将普及的因特网视频格式.HTML5 .Flash 播放器以及优酷等视频网站均支持它. 格式 文件 描述 AVI .avi AVI (Audio Video Inter ...
- java集合 collection-list-LinkedList
import java.util.*; /* LinkedList:特有方法: addFirst(); addLast(); getFirst(); getLast(); 获取元素,但不删除元素.如果 ...
- Windows下查询进程、端口
PID --> 端口号netstat -ano | findstr 8244 端口号 --> PIDnetstat -aon|findstr "11211" PID - ...
- Poj 1503 Integer Inquiry
1.链接地址: http://poj.org/problem?id=1503 2.题目: Integer Inquiry Time Limit: 1000MS Memory Limit: 1000 ...