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 解决Toast一直显示个不停的问题
做程序的时候最常用的弹出大概就是Toast了.但有时候会发先一个特别尴尬的问题,就是:一旦你点击某个按钮次数多了,即使在程序退出后,Toast也弹个不停.什么原因造成的呢? 是这样的:我们为了方便,在 ...
- odoo 学习
1.2.3.41.2.5.62.410.6变成1.234,1.256,2.4,10.6 def get_bom_namenum(self, cr, uid, ids, field_name, arg, ...
- session和cookie知识点总结
cookie小结:1.cookie是在服务端创建2.cooki是保存在浏览器这一端3.cookie的生命周期可以通过 cookie.setMaxAge(2000);(如果不设置生命周期,cookie的 ...
- 【SQL】MaxComputer中调试与问题排查技巧小结
1.分段调试 面对长的SQL,出错时一般直接看定位的行号,有时候不出错但是没数据时,应该尝试分段调试,很长的SQL嵌套很多的子查询时,一个一个子查询进行分别调试,看哪一步子查询出了问题,层层推进 2. ...
- WPF解决界面全屏化但不遮挡任务栏的问题
原文:WPF解决界面全屏化但不遮挡任务栏的问题 学习C#有一段时间了,现在跟着做项目,碰到有个客户端界面总是全屏,对于客户来说没有任务栏很不习惯,所以做了些略微的修改 </pre>&l ...
- python语言程序设计9
1, 数字转换形式中有很多东西都不会,但是总不能放仍不管把? 总结点东西吧,比如 print()中增加end=""参数表示输入后不增加换行,多个print可以连续输出. 2, 我还 ...
- C#断点续传下载。
断点续传 最近在优化之前的下载流程,仅此篇幅留作笔记之用,日后其他研究此类问题的伙伴可以马上了解原理和开发,减少开发成本. 原理:断点续传目前比较通用的是使用HTTP续传方式,相关的资料可以通过访问: ...
- 自己动手写把”锁”---LockSupport深入浅出
本篇是<自己动手写把"锁">系列技术铺垫的最后一个知识点.本篇主要讲解LockSupport工具类,它用来实现线程的挂起和唤醒. LockSupport是Java6引入 ...
- 从源码的角度看 React JS 中批量更新 State 的策略(上)
在之前的文章「深入理解 React JS 中的 setState」与 「从源码的角度再看 React JS 中的 setState」 中,我们分别看到了 React JS 中 setState 的异步 ...
- CAD2020下载安装AutoCAD2020中文版下载地址+安装教程
AutoCAD2020中文版为目前最新软件版本,我第一时间拿到软件进行安装测试,确保软件正常安装且各项功能正常可以使用,立刻拿出来分享,想用最新版本的话,抓紧下载使用吧: 我把我用的安装包贡献给你下载 ...