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 ...
随机推荐
- C#知识整理笔记
这里简单介绍了一些常用的属性,以及一些术语的解释和举例说明,不太全面,希望读者多多补充. 1.重载:函数名相同,参数的个数或参数类型不同; public void MyDog(string s); p ...
- KoaHub.JS用于Node.js的可移植Unix shell命令程序代码
shelljs Portable Unix shell commands for Node.js ShellJS - Unix shell commands for Node.js Shell ...
- NSPredicate 查询/搜索
IOS NSPredicate 查询.搜索 简述:Cocoa框架中的NSPredicate用于查询,原理和用法都类似于SQL中的where,作用相当于数据库的过滤取. 最常用到的函数 + (NSP ...
- Effective Modern C++ Item 37:确保std::thread在销毁时是unjoinable的
下面这段代码,如果调用func,按照C++的标准,程序会被终止(std::terminate) void func() { std::thread t([] { std::chrono::micros ...
- 实现在easyui中的datagrid,点击某一列的列头弹出combobox下拉框
easyUI datagrid在列头加下拉框,实现对列内容的筛选. 代码: onLoadSuccess: function (data) {//Fires when data is loaded s ...
- CentOS7搭建Confluence Wiki
前言 在艾佳生活实习时,有三款团队协作系统特别喜欢:Wiki.Jira和Jenkins.对于Jenkins的搭建,之前<自动部署工具Jenkins>有过记录.这次,搭建一个Wiki,作为知 ...
- download 下载文件 IE兼容性处理
根据CANIUSE(http://caniuse.com/#search=download)download兼容性如下图所示: 如上图所示,IE浏览器是不支持的. 1.测试代码: <!docty ...
- 000 Python之禅
The Zen of Python, by Tim Peters Beautiful is better than ugly.Explicit is better than implicit.Simp ...
- GitHub中最强大的iOS Notifications和AlertView框架,没有之一!
FFToast是一个非常强大的iOS message notifications和AlertView扩展.它可以很容易实现从屏幕顶部.屏幕底部和屏幕中间弹出一个通知.你可以很容易的自定义弹出的View ...
- iOS开发之UITableView及cell重用
1.UITanleview有的两种风格 一种是Plain,一种是Grouped,可以从这里设置风格: 他们样式分别如下: Plain: Grouped: 2.tableView展示数据的过程: (1) ...