题意:给定一个串长度<=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的更多相关文章

  1. 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 ...

  2. HDU 5008 Boring String Problem(后缀数组+二分)

    题目链接 思路 想到了,但是木写对啊....代码 各种bug,写的乱死了.... 输出最靠前的,比较折腾... #include <cstdio> #include <cstring ...

  3. HDOJ 5008 Boring String Problem

    后缀数组+RMQ+二分 后缀数组二分确定第K不同子串的位置 , 二分LCP确定可选的区间范围 , RMQ求范围内最小的sa Boring String Problem Time Limit: 6000 ...

  4. HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given ...

  5. HDU5008 Boring String Problem(后缀数组)

    练习一下字符串,做一下这道题. 首先是关于一个字符串有多少不同子串的问题,串由小到大排起序来应该是按照sa[i]的顺序排出来的产生的. 好像abbacd,排序出来的后缀是这样的 1---abbacd ...

  6. hdu 5008 查找字典序第k小的子串

    Boring String Problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Ot ...

  7. hdu String Problem(最小表示法入门题)

    hdu 3374 String Problem 最小表示法 view code#include <iostream> #include <cstdio> #include &l ...

  8. HDU 3374 String Problem(KMP+最大/最小表示)

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  9. HDU 3374 String Problem (KMP+最大最小表示)

    HDU 3374 String Problem (KMP+最大最小表示) String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory ...

随机推荐

  1. JS完美运动框架

    这套框架实现了多物体,任意值,链式运动,多值运动,基本满足常见的需求. /* 功能:完美运动框架,可以实现多物体,任意值,链式运动,多值运动 版本:V1.0 兼容性:Chrome,FF,IE8+ (o ...

  2. ThinkPHP的配置

    ThinkPHP配置:conf目录下 'URL_PATHINFO_DEPR'=>'-',//修改URL的分隔符, 'TMPL_L_DELIM'=>'<{', //修改左定界符 'TM ...

  3. hadoop命令报错:权限问题

    root用户执行hadoop命令报错: [root@vmocdp125 conf]# hadoop fs -ls /user/ [INFO] 17:50:42 main [RetryInvocatio ...

  4. Windows Server 2008 R2安装IIS

    在"服务器管理器"中选择"添加角色".   在"服务器角色"步骤选择"Web 服务器(IIS)".   "角色 ...

  5. New Lantern Version Available Upgrade Lantern for improved blocking resistance!

    New Lantern Version Available Upgrade Lantern for improved blocking resistance! The new version: is ...

  6. oracle 12 C启动问题

    启动时出现以下报错信息: SQL> startup; ORA-48146: missing read, write, or exec permission on directory during ...

  7. Oracle Text Slowly

    When  oracle text more and more slowly, execute the following script: ANALYZE TABLE Table_Name COMPU ...

  8. Hudson的安装配置

    Hudson的安装配置   目录 一.正文... 2 1.安装配置jdk. 2 2.安装配置tomcat7. 2 3.安装Hudson. 2 4.启动tomcat. 2 5.初识Hudson. 3 6 ...

  9. touches,motion触摸事件响应

    //触摸事件响应需要重写方法 1 // 触摸时触发该方法(消息发送) - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent: ...

  10. JavaScript 学习笔记: 扩充类型的功能

    JavaScript 是允许给基本类型扩充功能的.例如,可以通过对Object.prototype增加方法,可以让该方法对所有的对象都可用. 这样的方式对函数,数组,字符串,数字,正则表达式和布尔值同 ...