【洛谷】P3975 [TJOI2015]弦论(SAM)
题意
对于一个给定长度为 的字符串,求它的第 小子串。
数据范围
,,。
为 则表示不同位置的相同子串算作一个, 为 则表示不同位置的相同子串算作多个。
思路
考虑后缀自动机(下文默认已经知晓 SAM 的基本性质)。
根据题意,当 时,SAM 上的每个节点的 集合大小(该集合代表该节点对应的所有子串在原串中所有出现的位置)都为 。反之则可以根据 parent 树的性质从下往上递推。定义 点的 集合大小为 。
定义 表示经过 节点的子串数目(严格来说并不是,往后看就明白了)。即当前节点的 加上以当它为前缀的所有节点的 。可以在 SAM 的 DAG 上逆序递推。需要注意的是,这里不需要考虑 节点对应的所有子串,因为接下来查询的时候根据字典序的性质是从前往后推的,也就是一个前缀不断往后扩展,而不是后缀往前扩展(举个简单的例子,当前节点对应的子串集合为 {},那么后面查询到这里时可能是从 过来的,也可能是从 过来的,此时就与对应的其他子串无关了)。
查询的时候就是从根节点往后推,根据当前节点的 和 判断是否要继续往后推,具体实现可以见代码,这部分放在代码里将更清晰。
code
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+10;
#define LL long long
struct SAM{int ch[26],len,fa;}node[N];
int c[N],last=1,tot=1,t,k,num[N];LL siz[N],sum[N]; char s[N];
void extend(int c)
{
int p=last,np=last=++tot;node[np].len=node[p].len+1;siz[np]=1;
while(p&&!node[p].ch[c]) node[p].ch[c]=np,p=node[p].fa;
if(!p) node[np].fa=1;
else
{
int q=node[p].ch[c];
if(node[p].len+1==node[q].len) node[np].fa=q;
else
{
int nq=++tot;node[nq]=node[q];node[nq].len=node[p].len+1;
node[q].fa=node[np].fa=nq;
while(p&&node[p].ch[c]==q) node[p].ch[c]=nq,p=node[p].fa;
}
}
}
void print(int now,int k) //k表示当前还要查询的第k小子串
{
if(k<=siz[now]) return ; //如果当前节点出现次数不小于k,就代表查询子串就是当前已经走到的子串,不需要往后推
k-=siz[now];
for(int i=0;i<26;i++) //根据字典序的性质, 从小到大枚举当前位字符
{
int t=node[now].ch[i];if(!t) continue;
if(sum[t]<k) k-=sum[t];//有点类似于splay查询右子树时减去左子树的size
else {printf("%c",i+'a');print(t,k);return ;}
}
}
int main()
{
scanf("%s%d%d",s+1,&t,&k);for(int i=1;s[i];i++) extend(s[i]-'a');
for(int i=1;i<=tot;i++) c[node[i].len]++;//求siz和sum数组可以按照这里的基数排序的方式,也可以直接建图dfs
for(int i=1;i<=tot;i++) c[i]+=c[i-1];
for(int i=1;i<=tot;i++) num[c[node[i].len]--]=i;
for(int i=tot;i>=1;i--) siz[node[num[i]].fa]+=siz[num[i]];
for(int i=1;i<=tot;i++) t?sum[i]=siz[i]:siz[i]=sum[i]=1;
siz[1]=sum[1]=0;//需要注意,根节点没有任何信息,下面的sum[1]是判断无解
for(int i=tot;i>=1;i--)
for(int j=0;j<26;j++)
sum[num[i]]+=sum[node[num[i]].ch[j]];
if(sum[1]<k) puts("-1");
else print(1,k),puts("");
return 0;
}```
分类:
洛谷
标签:
后缀自动机(SAM)
, 字符串
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律