先看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弦论(后缀数组+二分答案)的更多相关文章

  1. BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案

    BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案 Description          给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l        读入单 ...

  2. Poj 1743 Musical Theme(后缀数组+二分答案)

    Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...

  3. Poj 3261 Milk Patterns(后缀数组+二分答案)

    Milk Patterns Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk g ...

  4. POJ3294--Life Forms 后缀数组+二分答案 大于k个字符串的最长公共子串

                                                                              Life Forms Time Limit: 500 ...

  5. SPOJ 220 Relevant Phrases of Annihilation(后缀数组+二分答案)

    [题目链接] http://www.spoj.pl/problems/PHRASES/ [题目大意] 求在每个字符串中出现至少两次的最长的子串 [题解] 注意到这么几个关键点:最长,至少两次,每个字符 ...

  6. POJ 3261 Milk Patterns(后缀数组+二分答案)

    [题目链接] http://poj.org/problem?id=3261 [题目大意] 求最长可允许重叠的出现次数不小于k的子串. [题解] 对原串做一遍后缀数组,二分子串长度x,将前缀相同长度超过 ...

  7. POJ 3294 Life Forms(后缀数组+二分答案)

    [题目链接] http://poj.org/problem?id=3294 [题目大意] 求出在至少在一半字符串中出现的最长子串. 如果有多个符合的答案,请按照字典序输出. [题解] 将所有的字符串通 ...

  8. POJ 1743 Musical Theme(后缀数组+二分答案)

    [题目链接] http://poj.org/problem?id=1743 [题目大意] 给出一首曲子的曲谱,上面的音符用不大于88的数字表示, 现在请你确定它主旋律的长度,主旋律指的是出现超过一次, ...

  9. POJ 1226 Substrings(后缀数组+二分答案)

    [题目链接] http://poj.org/problem?id=1226 [题目大意] 求在每个给出字符串中出现的最长子串的长度,字符串在出现的时候可以是倒置的. [题解] 我们将每个字符串倒置,用 ...

  10. POJ 3080 Blue Jeans(后缀数组+二分答案)

    [题目链接] http://poj.org/problem?id=3080 [题目大意] 求k个串的最长公共子串,如果存在多个则输出字典序最小,如果长度小于3则判断查找失败. [题解] 将所有字符串通 ...

随机推荐

  1. samba服务,连接远程开发机

    到了新环境,自己的开发机需要通过跳板机连,每次登录跳板机都需要RSA动态密码.一开始让我迷惑的是,这有个跳板机,那怎么让本地代码和开发机代码同步呢.以前公司的情况,一个是不需要跳板机,在phpstor ...

  2. C# 套接字编程:Scoket,我用Scoket做的C# Windows应用程序如下:

    首先请允许我做一个截图: 以上,是我服务端设计 我们知道:服务器端口数最大可以有65535个,但是实际上常用的端口才几十个,由此可以看出未定义的端口相当多.因此,我们可以通过程序随机获取一个当前可用的 ...

  3. koa2入门(2) koa-router 路由处理

    项目地址:https://github.com/caochangkui/demo/tree/koa-test 1. 创建项目 创建目录 koa-test npm init 创建 package.jso ...

  4. python第二周。2019.4.13

    1, 我绘制大蟒蛇就是..保存也对着呢,你要是打开文件的话,先闪个黑屏,再闪个白屏..自动退出,然后啥都没了. 我觉得是我代码编错了...再来一遍! 这次到可以,但是这个大蟒蛇好像没有回头... 刚才 ...

  5. item 2: 理解auto类型的推导

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 如果你已经读过item 1的模板类型推导,你已经知道大部分关于au ...

  6. SC1243sensor噪点问题调试

    接手一块SC1243sensor的板子调试,仔细核对了原理图和PCB发现,PCB不是很好,电源处理不够好,但是出图了,问题是有噪点,麻点,根据经验要求软件修改了PCLK的极性噪点消失,问题解决. 1: ...

  7. Python-习题-11

    1,内容回顾列表:增 append insert extend 删 remove pop clear del 改 li[索引] = '被修改的内容' li[切片]:'被修改的内容' 查 for循环 r ...

  8. Linux内核分析第五周学习总结

    扒开系统调用的三层皮(下) 20135237朱国庆+ 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/UST ...

  9. <<梦断代码>>阅读笔记三

    看完了这最后三分之一的<梦断代码>,意味着这本软件行业的著作已经被我粗略地过了一遍. 在这最后三分之一的内容中,我深入了解了在大型软件项目的运作过程中存在的困难和艰辛.一个大型软件项目的成 ...

  10. 数学战神app(小学生四则运算app)开发需求及进度

    项目名字:“数学战神” 开发环境:Android eclipse 团队名称:战神联盟 团队成员:陈思明,许家豪,王宏财,吴旭涛 在之前的四则运算APP中添加更多的实用功能,并在各种平台推广宣传. 预加 ...