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 ...
随机推荐
- 20160510--hibernate懒加载问题
懒加载 通过asm和cglib二个包实现:Domain是非final的. 1.session.load懒加载. 2.one-to-one(元素)懒加载: 必需同时满足下面三个条件时才能实现懒加载 (主 ...
- C# 打印文件
这几天做的功能用到了打印这个功能,直接在网上找了点demo,在这里做个备份. 1.直接打印DataTable using System; using System.Collections.Generi ...
- Aix命令大全
AIX服务器系统命令简介 在AIX操作系统上有很多的命令.这里介绍一些系统级的命令,它将有助于回答一些常见问题.大家以此做参考,并补充修改. 以下命令在AIX 5.1上测试通过. 正文 以下命令在AI ...
- Windows8安装Oracle11.2.0.1-0624,附带 DBCA建库、netca创建监听、配置PLSQL、定义客户端的环境变量 NLS_LANG、定义客户端的环境变量 TNS_ADMIN01
Windows8安装Oracle11.2.0.1 操作系统:Windows 8 企业版 64bit Oracle:11. ...
- C#上传图片和生成缩略图以及图片预览
因工作需要,上传图片要增加MIME类型验证和生成较小尺寸的图片用于浏览.根据网上代码加以修改做出如下效果图: 前台代码如下: <html xmlns="http://www.w3.or ...
- C# this关键字详解
this关键字主要有一下几个用途:1,this 用来引用当前类的实例,和扩展方法的第一个参数的修饰符 }2,限定被相似的名称隐藏的成员,例如: public Employee(string name, ...
- CBQW ---分组表单展示
工作流审核表单后,将表单信息展示页面中. Rest读取展示 展示方式有2 一. CBQW内容查询, 通过CBQW内容查询.分别通过设置itemstyle和header xsl ...
- lucene4.0 基于smb文件服务器的全文检索
使用lucene 4.0版本的全文检索 所需要的jar包 网速太慢,下次有空再把jar传上来 1.FileIndex 建立索引,查询,删除,更新 package com.strongit.tool ...
- 21_resultMap和resultType总结
[resultType] [ 作用 ] 将查询结果按照SQL列名与pojo属性名一致性 映射到pojo中. [ 使用场合 ] 常见的一些明细记录的展示,比如用户购买商品的明细,将关联查询信息全部展示在 ...
- 模板:函数memset
需要的头文件 <memory.h> or <string.h> memset 函数介绍 void *memset(void *s, int ch, size_t n); 函 ...