BZOJ 3998: [TJOI2015]弦论 SAM

匿名 (未验证) 提交于 2019-12-02 23:56:01

title

BZOJ 3998

LUOGU 3975

Description

对于一个给定的长度为 \(n\) 的字符串,求出它的第 \(k\) 小子串是什么。

analysis

建出 \(SAM\)\(K\) 大。

\(T=0\) 除了根以外的状态都代表 \(1\) 个串;

\(T=1\) 每个状态 \(fail\) 子树结束结点个数即为串的个数。

code

#include<bits/stdc++.h> using namespace std; const int maxn=5e5+10;  char buf[1<<15],*fs,*ft; inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; } template<typename T>inline void read(T &x) {     x=0;     T f=1, ch=getchar();     while (!isdigit(ch) && ch^'-') ch=getchar();     if (ch=='-') f=-1, ch=getchar();     while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();     x*=f; }  int T,K,n; struct SuffixAutoMaton {     int last,cnt;     int ch[maxn<<1][26],fa[maxn<<1],l[maxn<<1];//数据范围不计算清楚真是害死人     inline void extend(int c)     {         int p=last,np=++cnt;         last=cnt;         l[np]=l[p]+1;         for ( ; p && !ch[p][c]; p=fa[p]) ch[p][c]=np;         if (!p) fa[np]=1;         else         {             int q=ch[p][c];             if (l[p]+1==l[q]) fa[np]=q;             else             {                 int nq=++cnt;                 l[nq]=l[p]+1;                 memcpy(ch[nq],ch[q],sizeof(ch[q]));                 fa[nq]=fa[q];                 fa[q]=fa[np]=nq;                 for ( ; ch[p][c]==q; p=fa[p]) ch[p][c]=nq;             }         }         siz[np]=1;     }      int c[maxn],a[maxn<<1],siz[maxn<<1],sum[maxn<<1];//数据范围不计算清楚真是害死人     inline void calc()     {         for (int i=1; i<=cnt; ++i) ++c[l[i]];         for (int i=1; i<=n; ++i) c[i]+=c[i-1];//只需要计算出这个字符串实际长度的前缀即可         for (int i=cnt; i; --i) a[c[l[i]]--]=i;//倒序搞         for (int i=cnt; i; --i)//从小到大枚举,实际上在模拟parent树的DFS         {             int p=a[i];             if (T==1) siz[fa[p]]+=siz[p];             else siz[p]=1;         }         siz[1]=0;         for (int i=cnt; i; --i)         {             int p=a[i];             sum[p]=siz[p];             for (int j=0; j<26; ++j) sum[p]+=sum[ch[p][j]];         }     }      inline void dfs(int x,int K)     {         if (K<=siz[x]) return ;         K-=siz[x];         for (int i=0; i<26; ++i)             if (int p=ch[x][i])             {                 if (K<=sum[p])                 {                     putchar(i+'a');                     dfs(p,K);                     return ;                 }                 K-=sum[p];             }     } } SAM;  char s[maxn]; int main() {     scanf("%s",s+1);     n=strlen(s+1);SAM.cnt=SAM.last=1;//1为跟,表示空串     read(T);read(K);     for (int i=1; i<=n; ++i) SAM.extend(s[i]-'a');     SAM.calc();     if (K>SAM.sum[1]) puts("-1");     else SAM.dfs(1,K),puts("");     return 0; }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!