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 ...
随机推荐
- Oracle12c创建新用户提示公共用户名或角色无效
今天将备份的数据库还原到一台新的电脑上,首先要创建用户,执行如下语句: create user fxhy identified " default tablespace USERS temp ...
- C#开发微信门户及应用-使用地理位置扩展相关应用
C#开发微信门户及应用-使用地理位置扩展相关应用 我们知道,地理位置信息可以用来做很多相关的应用,除了我们可以知道用户所在的位置,还可以关联出一些地理位置的应用,如天气,热映影片,附近景点,附近影院, ...
- JavaScript生成GUID的多种算法小结
全局唯一标识符(GUID,Globally Unique Identifier)也称作 UUID(Universally Unique IDentifier) . GUID是一种由算法生成的二进制长度 ...
- ligerUI调用$.ligerDialog.open弹出窗口关闭
1:调用父窗口某一个文件框,获取焦点, parent.window.document.getElementById("roleName").focus(); 2:关闭父窗口 par ...
- Jquery 1.11.1 Checkbox checked 判断
if($(this).prop('checked'))
- 快速开启Windows 的各种任务及 bat(ch)脚本
MSC It is the Microsoft Management Console Snap-in Control File, like services.msc, devmgmt.msc (Dev ...
- LNK1169 和 LNK2005
错误重现: 1> vs2010创建 C++ win32 project, Application type: DLL. 2>为了在工程中使用 CString, 在 stdafx.h 中 I ...
- [技术翻译]构建现代化的 Objective-C (上)
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3561514.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- [Guava官方文档翻译] 3. 前置条件检查(Preconditions Explained)
本文地址:http://www.cnblogs.com/hamhog/p/3536964.html 前置条件检查 Guava提供了一些检查前置条件的utilities.我们强烈建议静态import这些 ...
- bzoj 1096: [ZJOI2007]仓库建设
dp是很好想的了,关键是数据太大,普通dp肯定超时,所以一定有用某种优化,dp优化也就那么几种,这道题用的是斜率优化,先写出普通的状态转移方程: dp[i] = min{ dp[j] + Σ ( p ...