BZOJ3998 TJOI2015弦论(后缀数组+二分答案)
先看t=1的情况。显然得求出SA(因为我不会SAM)。我们一位位地确定答案。设填到了第len位,二分这一位填什么之后,在已经确定的答案所在的范围(SA上的某段区间)内二分,找到最后一个小于当前串的后缀,那么从区间左端点到该位置的这些后缀的所有前缀都要比二分出的答案小,判一下是否合法。确定了这一位填什么之后,还要找到最后一个前len位小于等于当前串的后缀,若加上这一部分后比答案串小的已经超过k个的话,则答案已经确定可以直接退出了,否则将这些计入并继续填下一位,更新这些前len位等于答案串的后缀为答案范围。注意算的时候要减去已经计入的部分。
t=0类似,算出height数组后可以去掉重复子串。注意一些细节就好。
时间复杂度O(nlognlog|s|),s为字符集大小也就是26,跑的还挺快。
我怎么还不学SAM啊。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 500010
char a[N],ans[N];
int T,k,n,sa[N],sa2[N<<],rk[N<<],tmp[N<<],cnt[N],h[N];
long long sum[N];
void make()
{
memset(cnt,,sizeof(cnt));
int m=;
for (int i=;i<=n;i++) cnt[rk[i]=a[i]]++,m=max(m,(int)a[i]);
for (int i=;i<=m;i++) cnt[i]+=cnt[i-];
for (int i=n;i>=;i--) sa[cnt[rk[i]]--]=i;
for (int k=;k<=n;k<<=)
{
int p=;
for (int i=n-k+;i<=n;i++) sa2[++p]=i;
for (int i=;i<=n;i++) if (sa[i]>k) sa2[++p]=sa[i]-k;
memset(cnt,,m+<<);
for (int i=;i<=n;i++) cnt[rk[i]]++;
for (int i=;i<=m;i++) cnt[i]+=cnt[i-];
for (int i=n;i>=;i--) sa[cnt[rk[sa2[i]]]--]=sa2[i];
memcpy(tmp,rk,sizeof((rk)));
p=;rk[sa[]]=;
for (int i=;i<=n;i++)
{
if (tmp[sa[i]]!=tmp[sa[i-]]||tmp[sa[i]+k]!=tmp[sa[i-]+k]) p++;
rk[sa[i]]=p;
}
if (p>=n) break;
m=p;
}
}
int lower_find(int len,int l,int r,char c)
{
int ans=l-;
while (l<=r)
{
int mid=l+r>>;
if (a[sa[mid]+len-]<c) ans=mid,l=mid+;
else r=mid-;
}
return ans;
}
int upper_find(int len,int l,int r,char c)
{
int ans=l;
while (l<=r)
{
int mid=l+r>>;
if (a[sa[mid]+len-]<=c) ans=mid,l=mid+;
else r=mid-;
}
return ans;
}
int main()
{
freopen("bzoj3998.in","r",stdin);
freopen("bzoj3998.out","w",stdout);
scanf("%s",a+);n=strlen(a+);
cin>>T>>k;
make();
int len=;
if (T==)
{
for (int i=;i<=n;i++) sum[i]=sum[i-]+n-sa[i]+;
int l=,r=n;
while (len<=n)
{
len++;
char lc='a',rc='z';
while (lc<=rc)
{
char midc=lc+rc>>;
int x=lower_find(len,l,r,midc);
if (sum[x]-sum[l-]-(len-)*(x-l+)<k) lc=midc+,ans[len]=midc;
else rc=midc-;
}
int x=lower_find(len,l,r,ans[len]),y=upper_find(len,l,r,ans[len]);
k-=sum[x]-sum[l-]-(len-)*(x-l+)+y-x;
if (k<=) break;
l=x+,r=y;
}
}
else
{
for (int i=;i<=n;i++)
{
h[i]=max(h[i-]-,);
while (a[i+h[i]]==a[sa[rk[i]-]+h[i]]) h[i]++;
}
for (int i=;i<=n;i++) sum[i]=sum[i-]+n-sa[i]+-h[sa[i]];
int l=,r=n;
while (len<=n)
{
len++;
char lc='a',rc='z';
while (lc<=rc)
{
char midc=lc+rc>>;
int x=lower_find(len,l,r,midc);
if ((x==l-?:sum[x]-sum[l-]+h[sa[l]]-len+)<k) lc=midc+,ans[len]=midc;
else rc=midc-;
}
int x=lower_find(len,l,r,ans[len]),y=upper_find(len,l,r,ans[len]);
k-=(x==l-?:sum[x]-sum[l-]+h[sa[l]]-len+)+;
if (k<=) break;
l=x+,r=y;
}
}
if (k>) cout<<-;
else for (int i=;i<=len;i++) printf("%c",ans[i]);
fclose(stdin);fclose(stdout);
return ;
}
BZOJ3998 TJOI2015弦论(后缀数组+二分答案)的更多相关文章
- BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案
BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案 Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l 读入单 ...
- Poj 1743 Musical Theme(后缀数组+二分答案)
Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...
- Poj 3261 Milk Patterns(后缀数组+二分答案)
Milk Patterns Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk g ...
- POJ3294--Life Forms 后缀数组+二分答案 大于k个字符串的最长公共子串
Life Forms Time Limit: 500 ...
- SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)
[题目链接] http://www.spoj.pl/problems/PHRASES/ [题目大意] 求在每个字符串中出现至少两次的最长的子串 [题解] 注意到这么几个关键点:最长,至少两次,每个字符 ...
- POJ 3261 Milk Patterns(后缀数组+二分答案)
[题目链接] http://poj.org/problem?id=3261 [题目大意] 求最长可允许重叠的出现次数不小于k的子串. [题解] 对原串做一遍后缀数组,二分子串长度x,将前缀相同长度超过 ...
- POJ 3294 Life Forms(后缀数组+二分答案)
[题目链接] http://poj.org/problem?id=3294 [题目大意] 求出在至少在一半字符串中出现的最长子串. 如果有多个符合的答案,请按照字典序输出. [题解] 将所有的字符串通 ...
- POJ 1743 Musical Theme(后缀数组+二分答案)
[题目链接] http://poj.org/problem?id=1743 [题目大意] 给出一首曲子的曲谱,上面的音符用不大于88的数字表示, 现在请你确定它主旋律的长度,主旋律指的是出现超过一次, ...
- POJ 1226 Substrings(后缀数组+二分答案)
[题目链接] http://poj.org/problem?id=1226 [题目大意] 求在每个给出字符串中出现的最长子串的长度,字符串在出现的时候可以是倒置的. [题解] 我们将每个字符串倒置,用 ...
- POJ 3080 Blue Jeans(后缀数组+二分答案)
[题目链接] http://poj.org/problem?id=3080 [题目大意] 求k个串的最长公共子串,如果存在多个则输出字典序最小,如果长度小于3则判断查找失败. [题解] 将所有字符串通 ...
随机推荐
- Android学习之基础知识五—ListView控件(最常用和最难用的控件)
ListView控件允许用户通过上下滑动来将屏幕外的数据拉到屏幕内,把屏幕内的数据拉到屏幕外. 一.ListView的简单用法第一步:先创建一个ListViewTest项目,在activity_mia ...
- 你想要的Python面试都在这里了【315+道题】
写在前面 近日恰逢学生临近毕业,课程后期大家"期待+苦逼"的时刻莫过于每天早上内容回顾和面试题问答部分[临近毕业每天课前用40-60分钟对之前内容回顾.提问和补充,专挑班里不爱说话 ...
- python之魔法方法介绍
1.1. 简介 什么是魔法方法呢?它们在面向对象的Python的处处皆是.它们是一些可以让你对类添加“魔法”的特殊方法. 它们经常是两个下划线包围来命名的(比如 __init__ , __lt__ ) ...
- Ubuntu16.04下安装破解secureCRT和secureFX的操作记录
本地电脑之前安装的是win10,疲于win10频繁的更新和各种兼容问题,果断放弃win10系统,安装了Ubuntu 16.04系统,现在微信.QQ.钉钉.WPS等都已支持linux版本,所以在Ubun ...
- OpenVPN简单部署笔记
打算在IDC机房部署VPN环境,Openvpn也是一个不错的选择:开源,好用,而且免费. OpenVPN简单介绍OpenVPN是一个用于创建虚拟专用网络(Virtual Private Network ...
- restfull环境搭建-helloword(三)
原文地址:http://only81.iteye.com/blog/1689537 This section creates a CRUD (Create, Read, Update, Delete) ...
- M2项目测试
更为详细的测试报告,我们会在后续整理出来. 在M1的基础上,我们新增加了两个个数据表来存放问答对以及标签信息的表:C705question表 与 tag表 第二次迭代中,我们积极地同第三组沟通,了解到 ...
- 软工个人博客作业Week 1
问题1:在瀑布模型中提到模型,模型(模拟版本)和原型有什么不同,如果与原型有同样的功能,那为什么称之为模型?如果没有同样的功能,又是怎么测试那些程序的? 问题2:怎样才能高效率的广泛而深入地了解用户的 ...
- 同步手绘板——将View的内容映射成Bitmap转图片导出
在Android中自有获取view中的cache内容,然后将内容转换成bitmap,方法名是:getDrawingCache(),返回结果为Bitmap,但是刚开始使用的时候,得到的结果都是null, ...
- 趟坑:使用pip安装TensorFlow
这几天在安装TensorFlow,看了很多教程,方法也试了几种. 最后还是用pip安装成功的,过程如下. 1.安装ubuntu后在 系统设置-软件与更新-附加驱动 里,更新N卡驱动. (N卡官网下载 ...