HDU 5558 后缀数组+二分
题意有一些绕,但其实就是对于不断变化的i,求以j(0=j<i)使得suffix[j]与suffix[i]的最长公共前缀最长,如果有多个j,则取最小的j。
可以在rank数组中二分,在1-rank[i-1]中二分最接近i的j使得sa[j]小于i,通俗地说就是rank比的rank[i]小,并且位于i之前的后缀。因为这个是左边最接近rank[i]的,所以与suffix[i]的最长公共前缀一定是满足最大的。接下来再根据得到的LCP值,二分一个最小的j。同理,再从rank[i+1]到rank[n]中作类似二分。两者结合得到当前的K和T。
其实这道题中间过程也可以不用二分,直接向左右暴力扫。速度会快很多。
#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=1e5+; 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 wa[N], wb[N], cnt[N], wv[N];
int rk[N], height[N];
int sa[N];
bool cmp(int r[], int a, int b, int l) {
return r[a] == r[b] && r[a+l] == r[b+l];
}
void calcSA(char r[], int n, int m) {
int i, j, p, *x = wa, *y = wb;
for (i = ; i < m; ++i) cnt[i] = ;
for (i = ; i < n; ++i) cnt[x[i]=r[i]]++;
for (i = ; i < m; ++i) cnt[i] += cnt[i-];
for (i = n-; i >= ; --i) sa[--cnt[x[i]]] = i;
for (j = , p = ; p < n; j *= , m = p) {
for (p = , i = n - j; i < n; ++i) y[p++] = i;
for (i = ; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
for (i = ; i < n; ++i) wv[i] = x[y[i]];
for (i = ; i < m; ++i) cnt[i] = ;
for (i = ; i < n; ++i) cnt[wv[i]]++;
for (i = ; i < m; ++i) cnt[i] += cnt[i-];
for (i = n-; i >= ; --i) sa[--cnt[wv[i]]] = y[i];
for (swap(x, y), p = , x[sa[]] = , i = ; i < n; ++i)
x[sa[i]] = cmp(y, sa[i-], sa[i], j) ? p- : p++;
}
}
void calcHeight(char r[], int n) {
int i, j, k = ;
for (i = ; i <= n; ++i) rk[sa[i]] = i;
for (i = ; i < n; height[rk[i++]] = k)
for (k?k--:, j = sa[rk[i]-]; r[i+k] == r[j+k]; k++);
}
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][];
int preLog2[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-]);
}
preLog2[]=;
for(int i=;i<=n;i++){
preLog2[i]=preLog2[i-]+((i&(i-))==);
}
}
int queryST(int a,int b) {
if (a>b) swap(a,b);
int dis=b-a+;
int k=preLog2[dis];
return min(st[a][k],st[b-(<<k)+][k]);
}
void solve(int n) {
calcSA(s,n+,);
calcHeight(s,n);
initST(n);
rmq.setMin();
rmq.init(n,sa);
printf("-1 %d\n",s[]);
int i=;
while (i<n) {
int l=,r=rk[i]-;
int k=-,t=s[i];
int minIndex=-;
while (l<=r) {
int mid=(l+r)>>;
int minSA=rmq.query(mid,rk[i]-);
if (minSA<i)
l=mid+,minIndex=minSA;
else
r=mid-;
}
if (minIndex!=-) {
int u=lcp(minIndex,i,n);
if (u) {
k=u;
int l=,r=rk[i]-,ret=-;
while (l<=r) {
int mid=(l+r)>>;
int curLCP=lcp(sa[mid],i,n);
if (curLCP>=u)
r=mid-,ret=mid;
else l=mid+;
}
t=rmq.query(ret,rk[i]-);
}
}
l=rk[i]+;
r=n;
minIndex=-;
while (l<=r) {
int mid=(l+r)>>;
int minSA=rmq.query(rk[i]+,mid);
if (minSA<i)
r=mid-,minIndex=minSA;
else
l=mid+;
}
if (minIndex!=-) {
int u=lcp(minIndex,i,n);
if (u&&u>=k) {
if (u==k)
t=min(t,minIndex);
else
t=minIndex;
k=u;
int l=rk[i]+,r=n,ret=-;
while (l<=r) {
int mid=(l+r)>>;
int curLCP=lcp(sa[mid],i,n);
if (curLCP>=u)
l=mid+,ret=mid;
else r=mid-;
}
t=min(t,rmq.query(rk[i]+,ret));
}
}
if (k==-) {
printf("-1 %d\n",s[i]);
i++;
} else {
printf("%d %d\n",k,t);
i+=k;
}
}
}
} suf; int main () {
int T;
scanf("%d",&T);
while (T--) {
scanf("%s",s);
int n=strlen(s);
static int cas=;
printf("Case #%d:\n",cas++);
suf.solve(n);
}
return ;
}
HDU 5558 后缀数组+二分的更多相关文章
- K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)
大意: 给定串s, q个询问(l,r,k), 求子串s[l,r]的第kk次出现位置. 这是一篇很好的题解: https://blog.csdn.net/sdauguanweihong/article/ ...
- HDU 5558 后缀数组
思路: 这是一个错误的思路, 因为数据水才过= = 首先求出来后缀数组 把rank插到set里 每回差i两边离i近的rank值,更新 如果LCP相同,暴力左(右)继续更新sa的最小值 //By Sir ...
- BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )
二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...
- hdu 3948 后缀数组
The Number of Palindromes Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 262144/262144 K (J ...
- BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案
BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案 Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l 读入单 ...
- 【bzoj4310】跳蚤 后缀数组+二分
题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个 ...
- BZOJ 1717 [USACO06DEC] Milk Patterns (后缀数组+二分)
题目大意:求可重叠的相同子串数量至少是K的子串最长长度 洛谷传送门 依然是后缀数组+二分,先用后缀数组处理出height 每次二分出一个长度x,然后去验证,在排序的后缀串集合里,有没有连续数量多于K个 ...
- POJ 1743 [USACO5.1] Musical Theme (后缀数组+二分)
洛谷P2743传送门 题目大意:给你一个序列,求其中最长的一对相似等长子串 一对合法的相似子串被定义为: 1.任意一个子串长度都大于等于5 2.不能有重叠部分 3.其中一个子串可以在全部+/-某个值后 ...
- Poj 1743 Musical Theme(后缀数组+二分答案)
Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...
随机推荐
- .NET入行之工作前
时间就像轻风一样,刻意感受的时候几乎把你吹倒,不留意的时候又从你身边轻轻飘走了:长此以后,我怕自己会变得麻木,忘记了原来的样子.所以还是决定给自己留点什么,万一哪天忘记了,还可以再翻起来. 工作两年的 ...
- 通过JS将BSAE64生成图片并下载
HTML:<div style="display:block;margin:0 auto;width:638px;height:795px;"><div id=& ...
- NodeJs开发的CLI——与telnet进行通信的聊天程序
前言: (在NodeJs中,我们想要开启一个tcp协议的做法就是引入net内置对象: const net = require('net'); ——ES6 var net = req ...
- django generic view - ListView
ListView (带分页) 1.带分页效果的基础模板 1) view from django.views.generic.list import ListView from employ.model ...
- 在windows上缓存git 密码
缓存git密码 一搜索 大部分都是在linux上的 . git config --global credential.helper cache 但在windows上pull或者push会报如下错误: ...
- java中的对象
对象 --计算机语言中的对象 通常,我们可以从一般事物的三个方面,去认识事物: 一.是什么? 二.为什么? 三.怎么样? 接下来,我们也利用这三个方面的思维,去 ...
- boost.asio源码阅读(1) - 从chat_server开始
1. 关于示例代码 chat 先从简单的入手, 在如下路径:boost_1_63_0/libs/asio/example/cpp11/chat中找到chat_server.cpp 查看其成员, pri ...
- web注册功能实现
开发工具:Eclipse Web前端语言:html+jsp 后端数据库:MySQL 数据库UI工具:Navicat for MySQL (根据网上各位前辈的信息,自学实现这个注册基本功能,以后要是学到 ...
- trimpath javascript的学习
TrimPath是javascript模板引擎. 这几天有一个项目涉及到trimpath这个框架,所以就花了一点时间研究了一下,这个框架和别的javascript框架不太一样的地方就是模板的概念,就是 ...
- Android -- 贝塞尔曲线公式的推导
1,最近看了几个不错的自定义view,发现里面都会涉及到贝塞尔曲线知识,深刻的了解到贝塞尔曲线是进阶自定义view的一座大山,so,今天先和大家来了解了解. 2,贝塞尔曲线作用十分广泛,简单举几个的栗 ...