您的位置:首页 > 其它

SPOJ SUBLEX Lexicographical Substring Search

2017-09-26 18:07 357 查看

SPOJ SUBLEX Lexicographical Substring Search

SAM,后缀自动机,计数

题意

给一个字符串S,将他的所有子串(去重)按字典序排序,给q个询问,问拍第k个子串是谁。

思路

后缀自动机的计数问题。后缀自动机每个状态都代表一个或几个字符串。统计每个节点能到达多少个跟他具有相同前缀的字符串。

换句话说就是统计每个点通过trans边能到多少个串。方法可以dfs,也可以基排。基排就是处理出拓扑序后从后往前更新。

处理好subamo数组后,查找时尽量走小的边。就获得了最终rank(k)的字符串。

代码

#include <bits/stdc++.h>
#define M(a,b) memset(a,b,sizeof(a))
typedef long long LL;
using namespace std;
const int MAXL=100005;
const int MAXS=26;

struct SAM
{
int n, len, st;
int maxlen[2*MAXL+10], minlen[2*MAXL+10], trans[2*MAXL+10][MAXS], slink[2*MAXL+10], subamo[2*MAXL+10];

int new_state(int _maxlen, int _minlen, int* _trans, int _slink)
{
n++;
maxlen
=_maxlen;
minlen
=_minlen;
subamo
=1;
for(int i=0; i<MAXS; i++)
{
if(_trans==NULL)
trans
[i]=0;
else
trans
[i]=_trans[i];
}
slink
=_slink;
return n;
}

int add_char(char ch, int u)
{
int c=ch-'a';
int z=new_state(maxlen[u]+1, -1, NULL, 0);
int v=u;
while(v!=0&&trans[v][c]==0)
{
trans[v][c]=z;
v=slink[v];
}
if(v==0)
{
minlen[z]=1;
slink[z]=1;
return z;
}
int x=trans[v][c];
if(maxlen[v]+1==maxlen[x])
{
minlen[z]=maxlen[x]+1;
slink[z]=x;
return z;
}
int y=new_state(maxlen[v]+1, -1, trans[x], slink[x]);

minlen[x]=maxlen[y]+1;
slink[x]=y;
minlen[z]=maxlen[y]+1;
slink[z]=y;
int w=v;
while(w!=0&&trans[w][c]==x)
{
trans[w][c]=y;
w=slink[w];
}
minlen[y]=maxlen[slink[y]]+1;
return z;
}
void init()
{
memset(maxlen, 0, sizeof(maxlen));
memset(minlen, 0, sizeof(maxlen));
memset(trans, 0, sizeof(maxlen));
memset(slink, 0, sizeof(maxlen));
n=0;
st=new_state(0, -1, NULL, 0);
}
void addstring(char* s, int len)
{
int la=st;
for(int i=0;i<len;i++)
{
la=add_char(s[i], la);
}
this->len=len;
}
int ji[MAXL+10], id[2*MAXL+10];
void prepare()
{
memset(ji, 0, sizeof(ji)), memset(id, 0, sizeof(id));
ji[0]=0;
for(int i=st;i<=n;i++) ji[maxlen[i]]++;
for(int i=1;i<=n;i++) ji[i]+=ji[i-1];
for(int i=st;i<=n;i++) id[ji[maxlen[i]]--]=i;
for(int i=n;i>=st;i--)
{
int now=id[i];
for(int j=0;j<MAXS;j++)
{
if(trans[now][j])
subamo[now]+=subamo[trans[now][j]];
}
}
}
void deal(int k)
{
int now=this->st;
string s="";
while(k&&now)
{
for(int i=0;i<MAXS;i++)
{
if(trans[now][i])
{
int to=trans[now][i];
if(subamo[to]>=k)
{
s.push_back('a'+i);
now=to;
k--;
break;
}
else
{
k-=subamo[to];
}
}
}
}
printf("%s\n", s.c_str());
}
}sam;

char s[MAXL];
int main()
{
scanf("%s", s);int n=strlen(s);
sam.init();
sam.addstring(s, n);
sam.prepare();
int q;scanf("%d", &q);
while(q--)
{
int k;scanf("%d", &k);
sam.deal(k);
}
//system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: