您的位置:首页 > 其它

SPOJ 7258 SUBLEX - Lexicographical Substring Search【SAM,我要报警x

2016-08-01 23:46 423 查看
题目大意:求不同字串中第K小的那个

反正是弦论简化版x

我觉得数据有锅【……反正弦论代码交上去WA了】

假设K<=不同子串的个数, 并在K大于这个个数时直接putchar('\n'),WA到炸裂【跪地

然而如果无论如何直接算的话…………MD过了【摊手

【然后为了这个调了好几天…………还以为自己SAM白学了x】

代码↓

#include<bits/stdc++.h>
#define MAXN 180057
//#define FLAZE_NAIVE
using namespace std; char read_s[MAXN>>1]; int Q,K;

struct t1{
int son[MAXN][26],pre[MAXN],dis[MAXN];
int lst,cnt;
int lth;
int p,np,q,nq;

void insert(int x){
dis[np=++cnt]=dis[p=lst]+1;
lst=np;
for(;p&&!son[p][x];p=pre[p]) son[p][x]=np;
if(!p) return pre[np]=1,void();
q=son[p][x];
if(dis[q]==dis[p]+1) pre[np]=q;
else{
dis[nq=++cnt]=dis[p]+1;
memcpy(son[nq],son[q],sizeof son[q]);
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
for(;p&&son[p][x]==q;p=pre[p]) son[p][x]=nq;
}
}

void build(){
lst=cnt=1;
scanf("%s",read_s);
lth=strlen(read_s);
for(int i=0;i<lth;++i) insert(read_s[i]-'a');
}

int f[MAXN];
int v[MAXN],s[MAXN];
void prep(){
for(int i=1;i<=cnt;++i) ++v[dis[i]];
for(int i=1;i<=lth;++i) v[i]+=v[i-1];
for(int i=1;i<=cnt;++i) s[v[dis[i]]--]=i;

for(int i=cnt;i;--i){
int k=s[i];
f[k]=1;
for(int j=0;j<26;++j)
if(son[k][j])
f[k]+=f[son[k][j]];
}
}

void solve(int k){
int now=1;
while(k){
for(int i=0;i<26;++i)
if(son[now][i]){
if(k<=f[son[now][i]]){
now=son[now][i],putchar('a'+i),--k;
break;
}
else
k-=f[son[now][i]];
}
}
}

#ifdef FLAZE_NAIVE
char tmp[MAXN>>1];
void dfs(int now,int stp){
for(int i=0;i<26;++i)
if(son[now][i]){
tmp[stp]='a'+i;
printf("%d ",f[son[now][i]]);
puts(tmp);
dfs(son[now][i],stp+1);
}
tmp[stp]=' ';
}
#endif
}SAM_s;

int main(){
SAM_s.build();
SAM_s.prep();

#ifdef FLAZE_NAIVE
SAM_s.dfs(1,0);
#endif
scanf("%d",&Q);
while(Q--){
scanf("%d",&K);
SAM_s.solve(K);
putchar('\n');
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: