hdu4691 Front compression(后缀数组)
Front compression
Time Limit: 5000/5000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others)
Total Submission(s): 1339 Accepted Submission(s): 496

The size of the input is 43 bytes, while the size of the compressed output is
40. Here, every space and newline is also counted as 1 byte.
Given the input, each line of which is a substring of a long string, what are sizes of it and corresponding compressed output?
The first line of each test case is a long string S made up of lowercase letters, whose length doesn't exceed 100,000. The second line contains a integer 1 ≤ N ≤ 100,000, which is the number of lines in the input. Each of the following N lines contains two
integers 0 ≤ A < B ≤ length(S), indicating that that line of the input is substring [A, B) of S.
frcode
2
0 6
0 6
unitedstatesofamerica
3
0 6
0 12
0 21
myxophytamyxopodnabnabbednabbingnabit
6
0 9
9 16
16 19
19 25
25 32
32 37
14 12
42 31
43 40
pid=5061">5061
5060 5059
pid=5058">
5058
pid=5057">
5057
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
#define maxn 100010
using namespace std;
char s[maxn];
int n,k,q;
int rank[maxn],sa[maxn],tmp[maxn],lcp[maxn];//lcp:0-n-1
bool cmp(int x,int y){
if(rank[x]!=rank[y]) return rank[x]<rank[y];
int sx=x+k<=n ? rank[x+k]:-1;
int sy=y+k<=n ? rank[y+k]:-1;
return sx<sy;
}
void build_sa(){
n=strlen(s);
for(int i=0;i<=n;i++){
sa[i]=i;
rank[i]=i<n ? s[i]:-1;
}
for(k=1;k<=n;k<<=1){
sort(sa,sa+n+1,cmp);
tmp[sa[0]]=0;
for(int i=1;i<=n;i++){
tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i]) ? 1:0);
}
for(int i=0;i<=n;i++) rank[i]=tmp[i];
}
}
void build_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;
}
}
int dp[20][maxn],mm[maxn];
void init_RMQ(int n){
mm[0]=-1;
for(int i=1;i<=n;i++){//长度1-n
mm[i]=(i&(i-1)) ? mm[i-1]:mm[i-1]+1;
}
for(int i=0;i<n;i++) dp[0][i]=lcp[i];
for(int i=1;i<=mm[n];i++){
for(int j=0;j+(1<<i)-1<n;j++){
dp[i][j]=min(dp[i-1][j],dp[i-1][j+(1<<i>>1)]);
}
}
}
int RMQ(int x,int y){//[x,y-1]
if(x==y) return n-x;
x=rank[x],y=rank[y];
if(x>y) swap(x,y);
y--;
int l=mm[y-x+1];
return min(dp[l][x],dp[l][y-(1<<l)+1]);
}
void read(){
scanf("%d",&q);
ll sum1=0,sum2=0;
int pl=-1,pr=-1,l,r;
for(int i=0;i<q;i++){
scanf("%d%d",&l,&r);
sum1+=(r-l+1);
if(pl==-1){
sum2+=r-l+1;
}else{
int LCP=RMQ(pl,l);
int ans=min(LCP,min(r-l,pr-pl));
sum2+=(r-l-ans);
if(ans==0) sum2+=1;
else sum2+=(int)log10(ans*1.0)+1;
}
pl=l,pr=r;
}
printf("%I64d %I64d\n",sum1,sum2+2*q);
}
int main(){
while(~scanf("%s",s)){
build_sa();
build_lcp();
init_RMQ(n);
read();
}
return 0;
}
板子2:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
#define maxn 100010
using namespace std;
char s[maxn];
int c[maxn],wa[maxn],wb[maxn],r[maxn];//求SA数组须要的中间变量,不须要赋值
//待排序的字符串放在s数组中,从s[0]到s[n-1],长度为n,且最大值小于m,
//除s[n-1]外的全部s[i]都大于0,r[n-1]=0
//函数结束以后结果放在sa数组中
int n,sa[maxn],lcp[maxn],rank[maxn];
bool cmp(int *r,int a,int b,int l){
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void build_sa(int n,int m){//数组长度,最大数字
for(int i=0;i<=n;i++) r[i]=i<n ? s[i]:0;
n++;
int i,j,p,*x=wa,*y=wb;
//第一轮基数排序。假设s的最大值非常大,可改为高速排序
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[i]=r[i]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(j=1;j<=n;j<<=1){
p=0;
//直接利用sa数组排序第二keyword
for(i=n-j;i<n;i++) y[p++]=i;//后面的j个数第二keyword为空的最小
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
//这样数组y保存的就是依照第二keyword排序的结果
//基数排序第一keyword
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[y[i]]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
//依据sa和x数组计算新的x数组
swap(x,y);
p=1,x[sa[0]]=0;
for(i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
if(p>=n) break;
m=p;
}
}
void build_lcp(int n){
int i,j,k=0;
for(i=0;i<=n;i++) rank[sa[i]]=i;
lcp[0]=0;
for(i=0;i<n;i++){
j=sa[rank[i]-1];
if(k) k--;
while(s[i+k]==s[j+k]) k++;
lcp[rank[i]-1]=k;
}
}
int dp[20][maxn],mm[maxn];
void init_RMQ(int n){
mm[0]=-1;
for(int i=1;i<=n;i++){
mm[i]=(i&(i-1)) ? mm[i-1]:mm[i-1]+1;
}
for(int i=0;i<n;i++) dp[0][i]=lcp[i];
for(int i=1;i<=mm[n];i++){
for(int j=0;j+(1<<i)-1<n;j++){
dp[i][j]=min(dp[i-1][j],dp[i-1][j+(1<<i>>1)]);
}
}
}
int RMQ(int x,int y){
if(x==y) return n-x;
x=rank[x],y=rank[y];
if(x>y) swap(x,y);
y--;
int l=mm[y-x+1];
return min(dp[l][x],dp[l][y-(1<<l)+1]);
}
int q;
void read(){
scanf("%d",&q);
ll sum1=0,sum2=0;
int pl=-1,pr=-1,l,r;
for(int i=0;i<q;i++){
scanf("%d%d",&l,&r);
sum1+=(r-l+1);
if(pl==-1){
sum2+=r-l+1;
}else{
int LCP=RMQ(pl,l);
//cout<<i<<":"<<LCP<<endl;
int ans=min(LCP,min(r-l,pr-pl));
//cout<<i<<":"<<ans<<endl;
sum2+=(r-l-ans);
if(ans==0) sum2+=1;
else sum2+=(int)log10(ans*1.0)+1;
}
pl=l,pr=r;
}
printf("%I64d %I64d\n",sum1,sum2+2*q);
}
int main(){
while(~scanf("%s",s)){
n=strlen(s);
build_sa(n,128);
build_lcp(n);
/*for(int i=0;i<n;i++){
cout<<i<<" "<<sa[i]<<" "<<lcp[i]<<endl;
}*/
init_RMQ(n);
read();
}
return 0;
}
hdu4691 Front compression(后缀数组)的更多相关文章
- HDU-4691 Front compression 后缀数组
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4691 后缀数组模板题,求出Height数组后,对Height做RMQ,然后直接统计就可以了... // ...
- hdu4691 Front compression ——暴力 || 后缀数组
link:http://acm.hdu.edu.cn/showproblem.php?pid=4691 暴力,数据明显太水了吧,n=10^5, O(n^2)的复杂度哎喂.想让大家暴力写直接让n=100 ...
- hdu 4691 Front compression (后缀数组)
hdu 4691 Front compression 题意:很简单的,就是给一个字符串,然后给出n个区间,输出两个ans,一个是所有区间的长度和,另一个是区间i跟区间i-1的最长公共前缀的长度的数值的 ...
- HDU 4691 Front compression (2013多校9 1006题 后缀数组)
Front compression Time Limit: 5000/5000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Othe ...
- HDU 4691 Front compression(后缀数组)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4691 题意:给出Input,求出Compressed output.输出各用多少字节. 思路:求后缀数 ...
- hdu4691(后缀数组)
算是后缀数组的入门题吧. 思路无比简单,要是直接套模板的话应该很容易秒掉. 关于后缀数组看高中神犇的论文就可以学会了 算法合集之<后缀数组——处理字符串的有力工具> 话说这题暴力是可以过了 ...
- bzoj 3172 单词 ac自动机|后缀数组
题目大意: 给定n个字符串连成了一篇文章,问每个字符串在这篇文章中出现的次数,可重复覆盖 这里ac自动机和后缀数组都可以做 当然后缀数组很容易就解决,但是相对时间消耗高 这里就只讲ac自动机了 将每个 ...
- HDU5853 Jong Hyok and String(二分 + 后缀数组)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5853 Description Jong Hyok loves strings. One da ...
- Ural1297 Palindrome(后缀数组)
[题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12406 [题意] 求最长回文子串. [思路] 将字符串 ...
随机推荐
- [NOI2018]你的名字(68pts) 后缀自动机
讲解在满分做法的博客中 Code: #include <cstdio> #include <algorithm> #include <cstring> #defin ...
- appium ios端自动化测试配置
一.安装环境介绍macOS 10.12.4 Xcode 8.3.2 适用机型:iOS9 及以上机型 二.Appium源码安装Xcode升级8.2之后不再支持UIAutomation,转而使用XCUIT ...
- 用shell写一个简单DHCP配置脚本
轩轩写的这个小脚本,主要是可以进行对dhcp服务的安装.简单配置.开启.关闭/查看状态等情况 使用呢非常简单,按照步骤进行准确的设置就可以啦 #!/bin/bashyum -y install dhc ...
- 2015,鬼王Xun和GGL比赛,带给我们无尽的欢乐
一如既往的风格,正文之前,先扯蛋~ 这篇文章好久就想写了,一直没有动笔,最近在忙于Android和iOS等技术研究,又忙于金融投资等方面的学习和写作.这个周末,把技术进度延缓了点,把很多闲杂的 ...
- (原创)VS2017 C# 运行 Javasrcipt RSA 加密用户名登录 Java开发的服务器
第一次写博客. 最近想做一个Web的自动登录,用户名和密码是RSA加密过的,后台是用的JAVA,我只会点C#,抓包什么都搞定了(使用的是Fiddler),不过由于C#和RSA的加密方式不同,我搞了N天 ...
- Qt之字典划词
简述 相信大家都用过词典吧!因为英语不太好...O(∩_∩)O~,所以经常进行划词翻译! 简述 实现 效果 源码 更多参考 实现 原理:鼠标移至某单词之上,获取鼠标位置,然后在对应位置进行取词,翻译! ...
- MYSQL源代码编译的变动
Mysql的安装,对于mysql不同版本号的mysql源代码编译方式不一样 5.6.2的版本号開始编译方式已经由 configure 变成了cmake方式 ,相关的新的 编译方式在mysql官网已经提 ...
- echarts 地图 动态 展示 结合css+js
echarts地图展示功能非常强大,官网上静态展示的样例非常多了,动态的资料少.研究了下.我眼下实现的通过ajax从server获取数据动态展示地图. 另外,我们有时候希望在地图之上做些自己定义的东西 ...
- Android体验高扩展艺术般的适配器
前言 本篇文章带大家体验一下一种具有扩展性的适配器写法. 这个适配器主要用于Item有多种的情况下.当然仅仅有一种类型也是适用的 实现 毫无疑问我们要继承BaseAdapter,重写getCount, ...
- LeakCanary:简单粗暴的内存泄漏检測工具
差点儿每一个程序猿在开发的过程中都会遇到内存泄漏.那么我们怎样检測到app是否哪里出现内存泄漏呢?square公司推出了一款简单粗暴的检測内存泄漏的工具-- LeakCanary 什么是内存泄漏? 内 ...