HDU 5008 求第k小子串
本题要求第k小的distinct子串,可以根据height数组,二分出这个第k小子串所在后缀的位置信息。由于题目要求子串起始下标尽可能小。所以再在rank数组中,二分出与当前后缀LCP大于等于所求子串长度的范围。通过RMQ求出这个范围中最小的sa。
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <string.h>
#include <stdio.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <cassert>
#include <sstream>
using namespace std; const int N=; int MIN(int a,int b){return a<b?a:b;}
int MAX(int a,int b){return a>b?a:b;} int val[N];
struct RMQ {
int dp[N][];
int (*cmp) (int,int);
void setMin(){cmp=MIN;}
void setMax(){cmp=MAX;}
void init(int n,int *val) {
for (int i=; i<=n; i++)
dp[i][]=val[i];
for (int j=; (<<j)<=n; j++) {
int k=<<(j-);
for (int i=; i+k<=n; i++)
dp[i][j]=cmp(dp[i][j-],dp[i+k][j-]);
}
}
int query(int a,int b) {
if (a>b) swap(a,b);
int dis=b-a+;
int k=log((double)dis)/log(2.0);
return cmp(dp[a][k],dp[b-(<<k)+][k]);
}
}rmq;
char s[N];
struct SuffixArray {;
int sa[N];
int t1[N],t2[N],c[N];
int rk[N],height[N];
long long sum[N];
inline int cmp(int *r,int a,int b,int l){
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void calcSA (char *s,int n,int m) {
int i,j,p,*x=t1,*y=t2;
for(i=;i<m;i++)c[i]=;
for(i=;i<n;i++)c[x[i]=s[i]]++;
for(i=;i<m;i++)c[i]+=c[i-];
for(i=n-;i>=;i--)sa[--c[x[i]]]=i;
for(j=;j<=n;j<<=){
p=;
for(i=n-j;i<n;i++)y[p++]=i;
for(i=;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; // 排名从小到大,如果pos比j大,则suffix(sa[i]-j)的第二关键字为p
for(i=;i<m;i++)c[i]=;
for(i=;i<n;i++)c[x[y[i]]]++;
for(i=;i<m;i++)c[i]+=c[i-];
for(i=n-;i>=;i--)sa[--c[x[y[i]]]]=y[i]; // 根据第二关键字从大到小,确定新一轮sa
swap(x,y);
p=;x[sa[]]=;
for(i=;i<n;i++)
x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
if(p>=n)break;
m=p;
}
}
void calcHeight(char *s,int n) {
int i,j,k=;
for(i=;i<=n;i++)rk[sa[i]]=i;
for(i=;i<n;i++){
if(k)k--; // h[i]>=h[i-1]-1
j=sa[rk[i]-]; // suffix(j)排名在suffix(i)前一位
while(s[i+k]==s[j+k])k++; // 暴力计算lcp
height[rk[i]]=k;
}
sum[]=;
for (int i=;i<=n;i++) sum[i]=sum[i-]+n-sa[i]-height[i];
}
int lcp(int a,int b,int len) {
if (a==b) return len-a;
int ra=rk[a],rb=rk[b];
if (ra>rb) swap(ra,rb);
return queryST(ra+,rb);
}
int st[N][];
void initST(int n) {
for (int i=;i<=n;i++)
st[i][]=height[i];
for (int j=;(<<j)<=n;j++) {
int k=<<(j-);
for (int i=; i+k<=n; i++)
st[i][j]=min(st[i][j-],st[i+k][j-]);
}
}
int queryST(int a,int b) {
if (a>b) swap(a,b);
int dis=b-a+;
int k=log((double)dis)/log(2.0);
return min(st[a][k],st[b-(<<k)+][k]);
}
void solve(int &l,int &r,long long k,int n) {
if (k<||k>sum[n]) {
l=;r=;
return;
}
int t=lower_bound(sum,sum+n+,k)-sum;
assert(t>=&&t<=n);
long long now=sum[t-];
int need=k-now;
l=sa[t],r=sa[t]+height[t]+need-;
int len=r-l+;
int le=t,ri=n,ret=l;
while (le<=ri) {
int mid=(le+ri)/;
if (lcp(sa[mid],l,n)>=len) {
le=mid+;
ret=mid;
} else ri=mid-;
}
l=rmq.query(t,ret);
l++;
r=l+len-;
}
}suf; int main () {
while (scanf("%s",s)!=EOF) {
int n=strlen(s);
suf.calcSA(s,n+,);
suf.calcHeight(s,n);
suf.initST(n);
rmq.setMin();
rmq.init(n,suf.sa);
int Q;
scanf("%d",&Q);
int l=,r=; //int cnt=0;
while (Q--) {
long long k;
scanf("%I64d",&k);
k^=(l^r);
k++;
//k=++cnt;
suf.solve(l,r,k,n);
printf("%d %d\n",l,r);
}
}
return ;
}
HDU 5008 求第k小子串的更多相关文章
- SPOJ SUBLEX 求第k小子串
题目大意: 对于一个给定字符串,找到其所有不同的子串中排第k小的子串 先构建后缀自动机,然后我们可以将整个后缀自动机看做是一个DAG图,那么我们先进行拓扑排序得到 *b[N] 对于每个节点记录一个sc ...
- BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串
http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...
- hdu 4217 Data Structure? 树状数组求第K小
Data Structure? Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- 「BZOJ3998」[TJOI2015] 弦论(第K小子串)
https://www.lydsy.com/JudgeOnline/problem.php?id=3998 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input ...
- [TJOI2015]弦论(第k小子串)
题意: 对于一个给定的长度为n的字符串,求出它的第k小子串. 有参数t,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个. 题解: 首先,因为t的原因,后缀数组较难实现, ...
- 树状数组求第k小的元素
int find_kth(int k) { int ans = 0,cnt = 0; for (int i = 20;i >= 0;i--) //这里的20适当的取值,与MAX_VAL有关,一般 ...
- 算法导论学习之线性时间求第k小元素+堆思想求前k大元素
对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思 ...
- 求第k小的数
题目链接:第k个数 题意:求n个数中第k小的数 题解: //由快速排序算法演变而来的快速选择算法 #include<iostream> using namespace std; const ...
- *HDU2852 树状数组(求第K小的数)
KiKi's K-Number Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
随机推荐
- [hdu2156]分数矩阵
Problem Description 我们定义如下矩阵:1/1 1/2 1/31/2 1/1 1/21/3 1/2 1/1矩阵对角线上的元素始终是1/1,对角线两边分数的分母逐个递增.请求出这个矩阵 ...
- 算法模板——Dinic网络最大流 2
实现功能:同Dinic网络最大流 1 这个新的想法源于Dinic费用流算法... 在费用流算法里面,每次处理一条最短路,是通过spfa的过程中就记录下来,然后顺藤摸瓜处理一路 于是在这个里面我的最大流 ...
- SEO-百度推出新算法如何应对
> 如何知道百度推出新算法百度推出算法的趋势> 学SEO目的做排名,长流量,赚钱> 最近一年百度搜索变动1> 2012年6月:6/22, 6/28事件,百度地震,4.5%网站被 ...
- Kali linux learning note
from:http://blog.sina.com.cn/s/blog_40983e5e0101dhz0.html 因为kali linux基于debian 7,当然要把这台Acer 4736 ...
- Redis-port安装使用实现redis迁移codis,以及简单redis pipe实现将mysql迁移redis
(0)Redis-port原理: 首先是看到下面这篇文档开始研究的redis-port http://www.itnpc.com/news/web/146085373656602.html 简要截图 ...
- win10环境下jdk1.8+Android Developer Tools Build: v22.3.0-887826的问题
最进换了新电脑,配置开发环境,最新的android studio 要求jdk1.8,所以想都没想就下载1.8. 之后为了一个原来的老项目,得使用adt,遂装之,遇到一下问题 1.ADT新建项目src下 ...
- CSS用足够大的纯色内阴影去覆盖掉谷歌input记住账号或密码时默认出现的黄色背景
在谷歌浏览器会默认记住账号,而记住账号之后其input的背景会变成黄色,解决的办法如下: input:-webkit-autofill { -webkit-box-shadow: 0px 1000px ...
- MySQL入门(下)
1. 课程回顾(很清晰明了) mysql基础 1)mysql存储结构: 数据库 -> 表 -> 数据 sql语句 2)管理数据库: 增加: create database 数据库 de ...
- Android Things教程:电气基础之直流电路理论
译者注:由于本人水平有限,译文中难免会出现概念模糊.晦涩难懂,如果实在没心思看下去,请发挥你的学习能动性,到原文中自行翻译,感谢!!!点这里,直达英文各种长句的世界. 好了,既然你选择继续往下看,那就 ...
- Hadoop/Spark开发环境配置
修改hostname bogon 为localhost 查看ip地址 [training@bogon ~]$ sudo hostname localhost [training@bogon ~]$ h ...