4556: [Tjoi2016&Heoi2016]字符串

Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 179 Solved: 94
[Submit][Status][Discuss]
Description

佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了
一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE
O,嫁给高富帅,走上人生巅峰。每个问题均有a,b,c,d四个参数,问你子串s[a..b]的所有子串和s[c..d]的最长公
共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?
Input

输入的第一行有两个正整数n,m,分别表示字符串的长度和询问的个数。接下来一行是一个长为n的字符串。接下来
m行,每行有4个数a,b,c,d,表示询问s[a..b]的所有子串和s[c..d]的最长公共前缀的最大值。1<=n,m<=100,000,
字符串中仅有小写英文字母,a<=b,c<=d,1<=a,b,c,d<=n
Output

对于每一次询问,输出答案。

Sample Input

5 5

aaaaa

1 1 1 5

1 5 1 1

2 3 2 3

2 4 2 3

2 3 2 4
Sample Output

1

1

2

2

2

开始想了一种O(logn)O(logn)(但是有些问题),大致是这样的。
可以发现在求lcplcp的时候用的是区间最小值,这样假如当求一个位置的最大lcplcp的时候,那肯定是找这个位置rankrank的前驱和后继是最优的,因为再往前找的话答案是不增的。
想到这点之后就直接写了个主席树。
主席树中可以存区间的元素个数和,查询的时候先查询一下区间和,再在区间中像平衡树那样看看需要往哪边走,就能lognlogn的找到前驱后继了。
但是这样直接找前驱后继会有个问题,比如这组数据:

5 1
aaaab
1 2 3 5

这组数据在找后继的时候找的是aaabaaab这个后缀,但是由于这个有区间长度的限制,所以最后找到的答案是11。但是更优的方案是找aaaabaaaab这个后缀,这样就可以得到22这个答案。
为了解决这个问题,就需要在外面套个二分答案,这个二分就相当于在选了aaabaaab这个后缀之后,可以继续往后选。也就相当于是二分的可选择区间的右端点。
时间复杂度是O(mlog2n)O(mlog^2n)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
const int M=4000000;
int n,m,o,s[N],t1[N],t2[N],c[N],sa[N],rank[N],height[N],st[N][20],Log[N],root[N],l[M],r[M],sum[M],siz;
inline int in(){int x=0;char ch=getchar();while(ch<'0'||ch>'9') ch=getchar();while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x;
}
inline bool cmp(int *y,int p,int q,int k){int o0=(p+k>=n)?-1:y[p+k];int o1=(q+k>=n)?-1:y[q+k];return o0==o1&&y[p]==y[q];
}
inline void build_sa(){int i,k,p,*x=t1,*y=t2;for(o=27,i=0;i<o;++i) c[i]=0;for(i=0;i<n;++i) ++c[x[i]=s[i]];for(i=1;i<o;++i) c[i]+=c[i-1];for(i=n-1;~i;--i) sa[--c[x[i]]]=i;for(k=1;k<=n;k<<=1){for(p=0,i=n-k;i<n;++i) y[p++]=i;for(i=0;i<n;++i) if(sa[i]>=k) y[p++]=sa[i]-k;for(i=0;i<o;++i) c[i]=0;for(i=0;i<n;++i) ++c[x[y[i]]];for(i=1;i<o;++i) c[i]+=c[i-1];for(i=n-1;~i;--i) sa[--c[x[y[i]]]]=y[i];swap(x,y);x[sa[0]]=0;o=1;for(i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i],sa[i-1],k)?o-1:o++;if(o>=n) break;}
}
inline void build_height(){int i,k=0,j;for(i=0;i<n;++i) rank[sa[i]]=i;for(i=0;i<n;++i){if(!rank[i]) continue;k=k?--k:k;j=sa[rank[i]-1];while(s[j+k]==s[i+k]) ++k;height[rank[i]]=k;}memset(st,127/3,sizeof(st));    for(i=0;i<n;++i) st[i][0]=height[i];for(j=1;j<=20;++j)for(i=0;i+(1<<(j-1))<n;++i)st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);for(j=0,i=1;i<=n;++i){if((1<<(j+1))<=i) ++j;Log[i]=j;}
}
inline int LCP(int x,int y){if(x>y) swap(x,y);int k=Log[y-x];++x;return min(st[x][k],st[y-(1<<k)+1][k]);
}
#define mid (L+R)/2
inline void insert(int L,int R,int x,int &y,int z){y=++siz;sum[y]=sum[x]+1;if(L>=R) return ;l[y]=l[x];r[y]=r[x];if(z<=mid) insert(L,mid,l[x],l[y],z);else insert(mid+1,R,r[x],r[y],z);
}
inline int query_sum(int L,int R,int x,int y,int left,int right){int now=0;if(y<x) return 0;if(left<=L&&right>=R) return sum[y]-sum[x];if(left<=mid) now+=query_sum(L,mid,l[x],l[y],left,right);if(right>mid) now+=query_sum(mid+1,R,r[x],r[y],left,right);return now;
}
inline int query_pre(int L,int R,int x,int y,int left,int right,int now){if(L==R) return L;if(sum[l[y]]-sum[l[x]]>=now) return query_pre(L,mid,l[x],l[y],left,right,now);else return query_pre(mid+1,R,r[x],r[y],left,right,now-(sum[l[y]]-sum[l[x]]));
}
inline int query_sub(int L,int R,int x,int y,int left,int right,int now){if(L==R) return L;if(sum[r[y]]-sum[r[x]]>=now) return query_sub(mid+1,R,r[x],r[y],left,right,now);else return query_sub(L,mid,l[x],l[y],left,right,now-(sum[r[y]]-sum[r[x]]));
}
int main(){int i,now,left,right;scanf("%d%d",&n,&m);for(i=0;i<n;++i){char ch=getchar();while(ch<'a'||ch>'z') ch=getchar();s[i]=ch-'a'+1;}build_sa();build_height();for(i=0;i<n;++i) insert(0,n,root[i],root[i+1],rank[i]);while(m--){int aa,bb,cc,dd;aa=in();bb=in();cc=in();dd=in();int L=0,R=bb-aa+1,maxn=0;while(L<R){now=query_sum(0,n,root[aa-1],root[bb-mid],0,rank[cc-1]-1);left=now?query_pre(0,n,root[aa-1],root[bb-mid],0,rank[cc-1],now):-1;now=query_sum(0,n,root[aa-1],root[bb-mid],rank[cc-1]+1,n);right=now?query_sub(0,n,root[aa-1],root[bb-mid],rank[cc-1],n,now):-1;int ans=0;if(left!=-1){int oo=min(LCP(left,rank[cc-1]),bb-sa[left]);ans=max(ans,min(dd-cc+1,oo));}if(right!=-1){int oo=min(LCP(rank[cc-1],right),bb-sa[right]);ans=max(ans,min(dd-cc+1,oo));}if(cc>=aa&&cc<=bb) ans=max(ans,min(dd,bb)-cc+1);maxn=max(maxn,ans);if(ans>=mid) L=mid+1;else R=mid;}printf("%d\n",maxn);}
}

[bzoj4556][TJOIHEOI2016]字符串相关推荐

  1. [BZOJ4556][TJOI2016HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 1360  Solved: 545 ...

  2. [BZOJ4556][Tjoi2016Heoi2016]字符串 主席树+二分+倍增+后缀自动机

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 1215  Solved: 484 ...

  3. Bzoj4556 [Tjoi2016Heoi2016]字符串

    Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 846  Solved: 327 Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了 ...

  4. Redis 笔记(11)— 文本协议 RESP(单行、多行字符串、整数、错误、数组、空值、空串格式、telnet 登录 redis)

    RESP 是 Redis 序列化协议Redis Serialization Protocol 的简写.它是一种直观的文本协议,优势在于实现异常简单,解析性能极好. ​ Redis 协议将传输的结构数据 ...

  5. Go 知识点(16)— 将枚举值转换为字符串

    package mainimport "fmt"// 将 int 声明 为 ChipType 芯片类型. type ChipType intconst (None ChipType ...

  6. HJ75 公共字符串计算

    描述 给定两个只包含小写字母的字符串,计算两个字符串的最大公共子串的长度. 注:子串的定义指一个字符串删掉其部分前缀和后缀(也可以不删)后形成的字符串. 输入描述: 输入两个只包含小写字母的字符串 输 ...

  7. C++ 笔记(36)— 接收输入字符串的几种方法

    C++中常见的几种输入字符串的方法如下: std::cin.std::cin.get().std::cin.getline().std::getline().std::gets().std::getc ...

  8. 算法基础(09)— 字符串常用操作

    1. 字符串定义 字符串 string 是由 n 个字符组成的一个有序整体 n >= 0.例如,s = "BEIJING" ,s 代表这个串的串名,BEIJING 是串的值. ...

  9. C++ 笔记(35)— std::to_string 转换整形数字为字符串

    1. 函数原型 string to_string (int val); string to_string (long val); string to_string (long long val); s ...

  10. Linux shell 学习笔记(8)— 使用结构化命令(if-then 语句、数值比较、字符串比较、文件比较、case 语句)

    1. 使用 if-then 语句 最基本的结构化命令就是if-then语句.if-then语句有如下格式. if command then ​ commands fi 或者 if command; t ...

最新文章

  1. 专访朱雷:昔日的游戏少年,如今的Python工匠
  2. JZOJ 4.1 B组 删数
  3. 去除字符串中的html标记及标记中的内容
  4. BZOJ2038: [2009国家集训队]小Z的袜子(hose)
  5. HBase-再看HBase
  6. the process cannot access the file because it is being used by another process
  7. 一次 Java 内存泄漏排查过程,涨姿势
  8. HDU1715 大菲波数【大数】
  9. 数据结构上机实践第14周项目1(4) - 验证算法(平衡二叉树)
  10. 《高效对话》— 综合素质提升书籍
  11. shell脚本学习指南——好书推荐
  12. 安科瑞智慧消防在城市综合体中的应用
  13. 笔记本电脑加一个机械硬盘后的配置工作
  14. Linux命令之timeout
  15. 安装软件—用安装包形式安装
  16. Idea 精准到类的打包方式:Artifacts 打包
  17. SQL注入的攻击与防御(简单篇)
  18. Linux命令行下载OneDrive分享链接中的文件
  19. 4月全球“.网址”域名总量排行榜:ZDNS份额仍超99%
  20. 使用多媒体API枚举音频设备 - zgl7903的专栏 - CSDNBlog

热门文章

  1. python绘制四边形,三角形图形案例
  2. [转载]类名.this与类名.class_-Chaz-_新浪博客
  3. 初次软件开发(总结篇 之二)_-Chaz-_新浪博客
  4. 2020年总结:敏而多思,宁静致远——纪念这风雨兼程的一年
  5. 怎样区分线性和非线性_线性与非线性的区别(线性分析、线性模型)
  6. java根据出生年月计算年龄
  7. oracle cdb能存数据嘛,ORACLE 12C 非CDB迁移CDB之克隆非CDB数据库
  8. 华硕天选2 安装3060显卡驱动方法
  9. PDF旋转使用的转换器有哪些
  10. aiohttp+aiofiles异步爬虫光速下载图片