hdu 4691 最长的共同前缀 后缀数组 +lcp+rmq
http://acm.hdu.edu.cn/showproblem.php?
pid=4691
去年夏天,更多的学校的种族称号。当时,没有后缀数组
今天将是,事实上,自己的后缀阵列组合rmq或到,但是,题意理解的一个问题,再折腾了很长时间,,,,
此处简单解释下题目例子吧,希望对读者有帮助 以最后一组数据为例
myxophytamyxopodnabnabbednabbingnabit
6
0 9
9 16
16 19
19 25
25 32
32 37
前两行不解释,题目叙述非常清楚
从第三行,0 9 指的是第一个字符串是从第一行的字符串的0-9 左闭右开,
下面5行同样
继续看题目的正文叙述的例子
那么压缩之后的第一个就是“0空格以及前9个字符外加一个换行”一共12个。下面几行相同的算法
注意假设公共前缀长度是24,那么按两个单元存储,这就是我写的Weishu函数的作用
上代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath> using namespace std; const int MAXN =100000+20; int n,k;//n=strlen(s);
int Rank[MAXN],tmp[MAXN],d[MAXN],st[MAXN][20],lcp[MAXN],sa[MAXN];
char s[MAXN]; /*使用Rank对sa排序*/
bool cmpSa(int i, int j)
{
if(Rank[i] != Rank[j])return Rank[i] < Rank[j];
else
{ /*以下的Rank[t],已经是以t开头长度小于等于k/2的。
sa[i]的名次,仅仅是以i开头的后缀,而长度不同*/
int ri = i+k <=n? Rank[i+k]:-1;
int rj = j+k <= n ? Rank[j+k]:-1;
return ri <rj;
}
} /*计算SA*/
void consa(char *s, int *sa)
{
for(int i=0;i<=n;i++){
sa[i]=i;Rank[i] = i < n?s[i]:-1;
} for(k=1;k<=n;k*=2)/*注意此代码中k是全局变量 别乱用,循环必须从1開始,由于0*2=0*/
{
sort(sa,sa+n+1,cmpSa);
tmp[sa[0]] = 0; /*此时tmp仅仅是暂存rank*/
for(int i=1;i<=n;i++){
tmp[sa[i]] = tmp[sa[i-1]] +(cmpSa(sa[i-1],sa[i])?1:0);
}
for(int i=0;i<=n;i++){
Rank[i] = tmp[i];
}
}
} void construct_lcp(char *s,int *sa,int *lcp)
{
//n=strlen(s);
for(int i=0; i<=n; i++)Rank[sa[i]]=i; int h=0;
lcp[0]=0;
for(int i=0;i<n;i++)
{
int j=sa[Rank[i]-1]; if(h>0)h--;
for(; j+h<n && i+h<n; h++)
{
if(s[j+h]!=s[i+h])break;
}
lcp[Rank[i]-1]=h;
}
} void InitRMQ(int nn)
{
int i,j;
for(d[0]=1,i=1;i<21;i++)d[i]=2*d[i-1];
for(i=0;i<nn;i++)st[i][0]=lcp[i];
///////////////////////////////
// for(int i=0;i<nn;i++)
//{
// printf("%s i=%d sa=%d rank=%d lcp=%d\n",s+sa[i],i,sa[i],Rank[i],lcp[i]);
// printf("||||||||%s lcp[rank]=%d\n",s+i,lcp[Rank[i]]);
// }
//////////////////////////////// int k=int( log(double(nn))/log(2.0)+1 );
for(j=1;j<k;j++)
for(i=0;i<nn;i++)
{
if(i+d[j-1]-1<nn)
{
st[i][j]=min(st[i][j-1],st[i+d[j-1]][j-1]);
}
else break;
}
} int weishu(int n)
{
if(n<10)return 1;
int ans=0;
while(n)
{
n/=10;
ans++;
}
return ans;
} int main()
{
//freopen("hdu4691.txt","r",stdin);
long long ansb,ansa;
int kk;
while(~scanf("%s",s))
{
ansb=ansa=0;
n=strlen(s);
consa(s,sa);
construct_lcp(s,sa,lcp); InitRMQ(n+1);
int num,l,r,x,y;
scanf("%d",&num);
int last=0,lastlen=0;
scanf("%d%d",&l,&r);
ansb+=r-l+1;
ansa+=r-l+3;
lastlen=r-l;
last=l;
for(int i=1;i<num;i++)
{
scanf("%d%d",&l,&r);
ansb+=r-l+1;
ansa+=r-l;
x=min(Rank[last],Rank[l]),y=max(Rank[last],Rank[l])-1;
kk = int( log(double(y-x+1))/log(2.0) );
int ret;
if(l == last)ret=n-l;
else ret=min(st[x][kk], st[y-d[kk]+1][kk]) ;
ret=min(ret, min(lastlen,r-l));
ansa =ansa-ret+weishu(ret)+2;
last=l;
lastlen=r-l;
}
printf("%I64d %I64d\n",ansb,ansa);
}
return 0;
}
再加一个rmq+后缀数组求最长公共前缀的模板吧
(事实上还没有測试,遇到题在測试)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath> using namespace std; const int MAXN =100000+20; int n,k;//n=strlen(s);
int Rank[MAXN],tmp[MAXN],d[MAXN],st[MAXN][20],lcp[MAXN],sa[MAXN];
char s[MAXN]; /*使用Rank对sa排序*/
bool cmpSa(int i, int j)
{
if(Rank[i] != Rank[j])return Rank[i] < Rank[j];
else
{ /*以下的Rank[t],已经是以t开头长度小于等于k/2的,
sa[i]的名次。仅仅是以i开头的后缀,而长度不同*/
int ri = i+k <=n? Rank[i+k]:-1;
int rj = j+k <= n ? Rank[j+k]:-1;
return ri <rj;
}
} /*计算SA*/
void consa(char *s, int *sa)
{
for(int i=0;i<=n;i++){
sa[i]=i;Rank[i] = i < n?s[i]:-1;
} for(k=1;k<=n;k*=2)/*注意此代码中k是全局变量 别乱用,循环必须从1開始。由于0*2=0*/
{
sort(sa,sa+n+1,cmpSa);
tmp[sa[0]] = 0; /*此时tmp仅仅是暂存rank*/
for(int i=1;i<=n;i++){
tmp[sa[i]] = tmp[sa[i-1]] +(cmpSa(sa[i-1],sa[i])?1:0);
}
for(int i=0;i<=n;i++){
Rank[i] = tmp[i];
}
}
} void construct_lcp(char *s,int *sa,int *lcp)
{
//n=strlen(s);
for(int i=0; i<=n; i++)Rank[sa[i]]=i; int h=0;
lcp[0]=0;
for(int i=0;i<n;i++)
{
int j=sa[Rank[i]-1]; if(h>0)h--;
for(; j+h<n && i+h<n; h++)
{
if(s[j+h]!=s[i+h])break;
}
lcp[Rank[i]-1]=h;
}
} void InitRMQ(int nn)
{
int i,j;
for(d[0]=1,i=1;i<21;i++)d[i]=2*d[i-1];
for(i=0;i<nn;i++)st[i][0]=lcp[i];
int k=int( log(double(nn))/log(2.0)+1 );
for(j=1;j<k;j++)
for(i=0;i<nn;i++)
{
if(i+d[j-1]-1<nn)
{
st[i][j]=min(st[i][j-1],st[i+d[j-1]][j-1]);
}
else break;
}
} int ansLcp(int a, int b)
{
int kk;
if(a == b)return n-a;//n是整个字符串的长度
x=min(Rank[a],Rank[b]),y=max(Rank[a],Rank[b])-1;
kk = int( log(double(y-x+1))/log(2.0) );
return min(st[x][kk], st[y-d[kk]+1][kk]) ;
} int Query(int Q)//Q次询问
{
int ans;
for(int i=0;i<Q;i++)
{
scanf("%d%d",&a,&b);
ans=ansLcp(a,b);
}
}
版权声明:本文博客原创文章,博客,未经同意,不得转载。
hdu 4691 最长的共同前缀 后缀数组 +lcp+rmq的更多相关文章
- UVA 11107 Life Forms——(多字符串的最长公共子序列,后缀数组+LCP)
题意: 输入n个序列,求出一个最大长度的字符串,使得它在超过一半的DNA序列中连续出现.如果有多解,按照字典序从小到大输出所有解. 分析:这道题的关键是将多个字符串连接成一个串,方法是用不同的分隔符把 ...
- URAL 1297 最长回文子串(后缀数组)
1297. Palindrome Time limit: 1.0 secondMemory limit: 64 MB The “U.S. Robots” HQ has just received a ...
- POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)+后缀数组模板
Milk Patterns Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 7586 Accepted: 3448 Cas ...
- (持续更新)虚树,KD-Tree,长链剖分,后缀数组,后缀自动机
真的就是讲课两天,吸收一个月呢! \(1.\)虚树 \(2.\)KD-Tree \(3.\)长链剖分 \(4.\)后缀数组 后缀数组 \(5.\)后缀自动机 后缀自动机
- poj 2774 Long Long Message 后缀数组LCP理解
题目链接 题意:给两个长度不超过1e5的字符串,问两个字符串的连续公共子串最大长度为多少? 思路:两个字符串连接之后直接后缀数组+LCP,在height中找出max同时满足一左一右即可: #inclu ...
- 【bzoj5073】[Lydsy1710月赛]小A的咒语 后缀数组+倍增RMQ+贪心+dp
题目描述 给出 $A$ 串和 $B$ 串,从 $A$ 串中选出至多 $x$ 个互不重合的段,使得它们按照原顺序拼接后能够得到 $B$ 串.求是否可行.多组数据. $T\le 10$ ,$|A|,|B| ...
- 【bzoj3879】SvT 后缀数组+倍增RMQ+单调栈
题目描述 (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示), ...
- HDU 5442 Favorite Donut(暴力 or 后缀数组 or 最大表示法)
http://acm.hdu.edu.cn/showproblem.php?pid=5442 题意:给出一串字符串,它是循环的,现在要选定一个起点,使得该字符串字典序最大(顺时针和逆时针均可),如果有 ...
- POJ1743 Musical Theme 最长重复子串 利用后缀数组
POJ1743 题目意思是求不重叠的最长相同变化的子串,输出该长度 比如1 2 3 4 5 6 7 8 9 10,最长长度为5,因为子串1 2 3 4 5 和 6 7 8 9 10变化都一样的 思路: ...
随机推荐
- 《Java并发编程实战》第七章 取消与关闭 读书笔记
Java没有提供不论什么机制来安全地(抢占式方法)终止线程,尽管Thread.stop和suspend等方法提供了这种机制,可是因为存在着一些严重的缺陷,因此应该避免使用. 但它提供了中断In ...
- 逆向 Framework.jar
Ref:http://www.addictivetips.com/mobile/what-is-odex-and-deodex-in-android-complete-guide/ Ref:http: ...
- SVN基于Maven的Web项目更新,本地过程详细解释
周围环境 MyEclipse:10.7 Maven:3.1.1 概要 最近在做项目,MyEclipse下载SVN基于上述Maven的Web问题,有时候搞了非常半天,Maven项目还是出现叉号,最后总结 ...
- Android开展:ADT+Eclipse使用错误:Text editor does not have a document provider
Eclipse参加Android sdk源代码 正在使用Eclipse进行Android开发时间,我们经常需要导入sdk源代码来Eclipse中,方便api阅读和查询,详细操作为:ctrl+鼠标左键. ...
- hadoop日志分析
一.项目要求 本文讨论的日志处理方法中的日志,仅指Web日志.事实上并没有精确的定义,可能包含但不限于各种前端Webserver--apache.lighttpd.nginx.tomcat等产生的用户 ...
- windows phone (16) UI变换 下
原文:windows phone (16) UI变换 下 上一篇中说到四个变换类,都是比较简单的,这里要说到四个变换类,分别为: MatrixTransfrom矩阵变换,一句标准矩阵表示的变换 Tra ...
- bc38 1002, bc39 1002
比赛的时候是对于每个数,记录下来a[i], 并记录该树的下标hash[a[i]] 然后枚举a[i]的倍数,如果a[i]的倍数存在(设为k*a[i]),那么vis[k*a[i]]是不为0的 那么可以这样 ...
- Windows Phone开发(23):启动器与选择器之CameraCaptureTask和PhotoChooserTask
原文:Windows Phone开发(23):启动器与选择器之CameraCaptureTask和PhotoChooserTask 这两个组件都属于选择器,而且它们也有很多相似的地方,最明显的上一点, ...
- hdu 4885 (n^2*log(n)推断三点共线建图)+最短路
题意:车从起点出发,每次仅仅能行驶L长度,必需加油到满,每次仅仅能去加油站或目的地方向,路过加油站就必需进去加油,问最小要路过几次加油站. 開始时候直接建图,在范围内就有边1.跑最短了,再读题后发现, ...
- 傻瓜式破解linux--rootpassword
破password的方法: 方法1.单用户模式改动 (表示进入到单用户模式) .按回车键.按b键启动.进入单用户模式,进行password改动.重新启动 init 5 口诀:e2e 空格1 回车b 开 ...