SA的话t0直接预处理出每个后缀的不同串贡献二分即可,然后t1就按字典序枚举后缀,然后跳右端点计算和当前后缀的前缀相同的子串个数,直到第k个

不过bzoj上会T

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=10000005;
int n,o,sa[N],rk[N],he[N],wa[N],wb[N],wsu[N],wv[N],st[20][N],b[N];
long long k,a[N],sm;
char s[N];
bool cmp(int r[],int a,int b,int l)
{
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void saa(char r[],int n,int m)
{
int *x=wa,*y=wb;
for(int i=0;i<=m;i++)
wsu[i]=0;
for(int i=1;i<=n;i++)
wsu[x[i]=r[i]]++;
for(int i=1;i<=m;i++)
wsu[i]+=wsu[i-1];
for(int i=n;i>=1;i--)
sa[wsu[x[i]]--]=i;
for(int j=1,p=1;j<=n&&p<n;j<<=1,m=p)
{
p=0;
for(int i=n-j+1;i<=n;i++)
y[++p]=i;
for(int i=1;i<=n;i++)
if(sa[i]>j)
y[++p]=sa[i]-j;
for(int i=1;i<=n;i++)
wv[i]=x[y[i]];
for(int i=0;i<=m;i++)
wsu[i]=0;
for(int i=1;i<=n;i++)
wsu[wv[i]]++;
for(int i=1;i<=m;i++)
wsu[i]+=wsu[i-1];
for(int i=n;i>=1;i--)
sa[wsu[wv[i]]--]=y[i];
swap(x,y);
p=1;
x[sa[1]]=1;
for(int i=2;i<=n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p:++p;
}
for(int i=1;i<=n;i++)
rk[sa[i]]=i;
for(int i=1,j,k=0;i<=n;he[rk[i++]]=k)
for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
}
int ques(int l,int r)
{
if(l>r)
return n-l+1;
int k=b[r-l+1];
return min(st[k][l],st[k][r-(1<<k)+1]);
}
int main()
{
scanf("%s%d%d",s+1,&o,&k);
n=strlen(s+1);
saa(s,n,200);
for(int i=1;i<=n;i++)
a[i]=a[i-1]+n-sa[i]+1-he[i];
if(o==0)
{
if(a[n]<k)
{
puts("-1");
return 0;
}
int l=1,r=n,ans=1;
while(l<=r)
{
int mid=(l+r)>>1;
if(a[mid]>=k)
r=mid-1,ans=mid;
else
l=mid+1;
}
for(int i=sa[ans];i<=n-a[ans]+k;i++)
putchar(s[i]);
return 0;
}
b[0]=-1;
for(int i=1;i<=n;i++)
b[i]=b[i>>1]+1;
for(int i=1;i<=n;i++)
st[0][i]=he[i];
for(int i=1;i<=19;i++)
for(int j=1;j<=n;j++)
st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
for(int i=1;i<=n;i++)
{
int nw=sa[i]+he[i],ed=n;
while(1)
{//cerr<<i<<" "<<ed<<endl;
if(nw>n)
break;
if(ed==i)
{
if(k>n-nw+1)
{
k-=n-nw+1;
break;
}
for(int j=sa[i];j<=nw+k-1;j++)
putchar(s[j]);
return 0;
}
int l=i,r=ed;
while(l<=r)
{
int mid=(l+r)>>1;
if(ques(i+1,mid)>=nw-sa[i]+1)
l=mid+1,ed=mid;
else
r=mid-1;
}
if(k>ed-i+1)
k-=ed-i+1;
else
{
for(int j=sa[i];j<=nw;j++)
putchar(s[j]);
return 0;
}
nw++;
}
}
puts("-1");
return 0;
}

SAM的话就利用trie树的性质,t0就每个点size=1,t1就每个点计算一下parent树上这个点下面有几个后缀终止点

然后计算trie树上的子树size和,枚举转移字符直到第k个即可

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000006;
int n,o,k,fa[N],ch[N][26],tot=1,cur=1,la,dis[N],wsu[N],sa[N];
long long si[N],sm[N],ans;
char s[N];
void ins(int c,int id)
{
la=cur,dis[cur=++tot]=id;
si[cur]=1;
int p=la;
for(;p&&!ch[p][c];p=fa[p])
ch[p][c]=cur;
if(!p)
fa[cur]=1;
else
{
int q=ch[p][c];
if(dis[q]==dis[p]+1)
fa[cur]=q;
else
{
int nq=++tot;
dis[nq]=dis[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];
fa[q]=fa[cur]=nq;
for(;ch[p][c]==q;p=fa[p])
ch[p][c]=nq;
}
}
}
int main()
{
scanf("%s%d%d",s+1,&o,&k);
n=strlen(s+1);
for(int i=1;i<=n;i++)
ins(s[i]-'a',i);
for(int i=1;i<=tot;i++)
wsu[dis[i]]++;
for(int i=1;i<=n;i++)
wsu[i]+=wsu[i-1];
for(int i=tot;i>=1;i--)
sa[wsu[dis[i]]--]=i;
for(int i=tot;i>=1;i--)
o?si[fa[sa[i]]]+=si[sa[i]]:si[sa[i]]=1;
si[1]=0;
for(int i=tot;i>=1;i--)
{
sm[sa[i]]=si[sa[i]];
for(int j=0;j<26;j++)
if(ch[sa[i]][j])
sm[sa[i]]+=sm[ch[sa[i]][j]];
}
if(sm[1]<k)
{
puts("-1");
return 0;
}
int nw=1;
while((k-=si[nw])>0)
{
int w;
for(int i=0;i<26;i++)
if(ch[nw][i])
{
if(sm[ch[nw][i]]<k)
k-=sm[ch[nw][i]];
else
{
w=i;
break;
}
}
putchar(w+'a');
nw=ch[nw][w];
}
return 0;
}

bzoj 3998: [TJOI2015]弦论【SA+二分||SAM】的更多相关文章

  1. BZOJ 3998: [TJOI2015]弦论 [后缀自动机 DP]

    3998: [TJOI2015]弦论 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2152  Solved: 716[Submit][Status] ...

  2. ●BZOJ 3998 [TJOI2015]弦论

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3998题解: 后缀自动机. 当T=0时, 由于在后缀自动机上沿着trans转移,每个串都是互不 ...

  3. BZOJ 3998 TJOI2015 弦论 后缀自动机+DAG上的dp

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3998 题意概述:对于一个给定长度为N的字符串,求它的第K小子串是什么,T为0则表示不同位置 ...

  4. BZOJ 3998 [TJOI2015]弦论 ——后缀自动机

    直接构建后缀自动机. 然后. 然后只需要再后缀自动机的go树上类似二分的方法进行查找即可,实际上是“26分”. 然后遇到了处理right集合的问题,然后觉得在go和parent树上上传都是可以的,毕竟 ...

  5. bzoj 3998: [TJOI2015]弦论

    Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个. ...

  6. BZOJ.3998.[TJOI2015]弦论(后缀自动机)

    题目链接 \(Description\) 给定字符串S,求其第K小子串.(若T=0,不同位置的相同子串算1个:否则算作多个) \(Solution\) 建SAM,处理出对于每个节点,它和它的所有后继包 ...

  7. BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串

    http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...

  8. 【刷题】BZOJ 3998 [TJOI2015]弦论

    Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个. ...

  9. bzoj 3998 [TJOI2015]弦论——后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3998 相同子串算多个的话,先求好 right ,然后求一个 sm 表示走到这个点之后有几种走 ...

随机推荐

  1. 向量空间模型实现文档查询(Vector Space Model to realize document query)

    xml中文档(query)的结构: <topic> <number>CIRB010TopicZH006</number> <title>科索沃難民潮&l ...

  2. HashMap变成线程安全方法

    我们都知道.HashMap是非线程安全的(非同步的).那么怎么才能让HashMap变成线程安全的呢? 我认为主要可以通过以下三种方法来实现: 1.替换成Hashtable,Hashtable通过对整个 ...

  3. Python演绎的精彩故事(二)

    书接上回.在展示了App最顶层的代码后,我们去看看各模块怎样编程. 为了能看懂各模块的代码,首先须要铺垫一下Softchip架构的基本概念和设计规范. 1.随意模块不持有其它模块的实例.自然不再显式使 ...

  4. Python 包的制作(__init__.py)

    如何制作一个自己的包:首先,需要创建一个文件夹,将其作为顶层包,在此文件夹内我们可以定义各个不同的子文件夹与 .py 文件作为各个子包与模块注意:在每个包文件夹下都需要有一个 __init__.py ...

  5. C#高阶与初心:(二)P/Invoke平台调用

    最近某个项目要采集交易终端的信息用于监管,主要厂商给出了API,C++版的...开启hard模式!!! C#调用C++的DLL基本就两种方法:加一个VC++项目包一层,或者使用P/Invoke(平台调 ...

  6. Python开发【2.1 面向对象】

    1.面向对象概述 类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 类变量:类变量在整个实例化的对象中是公用的.类变量定义在类 ...

  7. 如何解决Windows的端口占用问题?

    已知某应用在启动时会创建服务套接字,并将其绑定至端口8888,然而端口8888已被占用,如何解除占用? 以下为解决方案: 在cmd中运行netstat -ano|findstr 8888,其中的参数8 ...

  8. (25) java web的struts2框架的使用-基于表单的文件上传

    一,首先创建一个表单页面 <body> <form action="uploads" method="post" enctype=" ...

  9. STM32低功耗模式与烟雾报警器触发信号电路设计

    1.STM32的3种低功耗模式 STM32有3种低功耗模式,分别是睡眠模式.停机模式和待机模式. 2.STM32在不同模式下的电流消耗 a.工作模式  消耗电流在27mA至36mA之间. b.睡眠模式 ...

  10. ERROR: cannot start Android Studio. No JDK found. Please validate either ANDROID_STUDIO_JDK, JDK_HOME + Unrecognized VM option '+UseCodeCacheFlushing

    想学下android,在本来想用myeclipse安装下sdk和adt,谁知在官网看到http://developer.android.com/sdk/index.html Google I/O 20 ...