先看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. Luogu P1082 同余方程(exgcd模版)

    传送门 求ax%b = 1,即ax - by = 1: 很明显这是一个exgcd的形式. 那么要做这道题,首先需要gcd和exgcd的算法作铺垫. gcd(辗转相膜法): int gcd(int a, ...

  2. Spring @Scheduled定时任务的fixedRate,fixedDelay,cron执行差异

    import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import org.sp ...

  3. 5-(基础入门篇)学会刷Wi-Fi模块固件(刷LUA版本固件)

    http://www.cnblogs.com/yangfengwu/p/9065559.html 基础教程源码链接请在淘宝介绍中下载,由于链接很容易失效,如果失效请联系卖家,谢谢 https://it ...

  4. Vue-接口跨域请求调试proxyTable

    在项目开发的时候,接口联调的时候一般都是同域名下,且不存在跨域的情况下进行接口联调,但是当我们现在使用vue-cli进行项目打包的时候,我们在本地启动服务器后,比如本地开发服务下是 http://lo ...

  5. js 稍微判断下浏览器 pc 还是手机

        function isMobile() {    var a=navigator.userAgent;   var ref=/.*(Android|iPhone|SymbianOS|iPad| ...

  6. 【php增删改查实例】第十七节 - 用户登录(1)

    新建一个login文件,里面存放的就是用户登录的模块. <html> <head> <meta charset="utf-8"> <sty ...

  7. 并行管理工具——pdsh

    1. pdsh安装2. pdsh常规使用2.1 pdsh2.2 pdcp 并行管理的方式有很多种: 命令行 一般是for循环 脚本 一般是expect+ssh等自编辑脚本 工具 pssh,pdsh,m ...

  8. Thrift_简介(基于C#)

    //Server: TProtocolFactory ProtocolFactory = new TBinaryProtocol.Factory(true, true); TTransportFact ...

  9. html绝对路径,相对路径

    .com/eat.php中引用.com/includes/headrt.php的话写includes/header.php .com/service/eat.php中引用.com/includes/h ...

  10. Linux下通过受限bash创建指定权限的账号

    在日常业务运维中,有时为了配合解决问题,需要给非运维人员开通系统账号,用于查询日志或代码.通常为了系统安全或避免不必要的误操作等目的,会将账号权限降至最低.下面介绍下在Linux下通过受限bash创建 ...