SP7258 Lexicographical Substring Search 題解
阿新 • • 發佈:2022-05-18
本質不同第 \(k\) 小。對 SAM 上每個點求一個 \(b_i\) 表示從這個點開始往後走能走到的本質不同的子串個數。然後拿 \(k\) 在自動機上跑即可。
點選檢視程式碼
const int N=9e4+13; char s[N]; int nxt[N<<1],len[N<<1],ptot=1,lastpos=1,c[N<<1],ind[N<<1],a[N<<1],ans[N]; ll b[N<<1]; std::unordered_map<int,int> son[N<<1],zrzak; inline int newpos(std::unordered_map<int,int> nson,int nlen){return len[++ptot]=nlen,std::swap(son[ptot],nson),ptot;} inline void insert(int c){ int p=lastpos,u=newpos(zrzak,len[p]+1); while(p&&son[p].find(c)==son[p].end()) son[p][c]=u,p=nxt[p]; lastpos=u; if(!p) return nxt[u]=1,void(); int d=son[p][c]; if(len[d]==len[p]+1) nxt[u]=d; else{ int v=newpos(son[d],len[p]+1); nxt[v]=nxt[d],nxt[d]=nxt[u]=v; while(p&&son[p][c]==d) son[p][c]=v,p=nxt[p]; } } inline void inittopo(){ std::queue<int> q;q.push(1); for(int i=1;i<=ptot;++i) for(int j=0;j<26;++j) if(son[i].find(j)!=son[i].end()) ind[son[i][j]]++; int tot=0; while(!q.empty()){ int u=q.front();q.pop(); a[++tot]=u; for(int i=0;i<26;++i) if(son[u].find(i)!=son[u].end()) if(!(--ind[son[u][i]])) q.push(son[u][i]); } } int main(){ read(s+1);int n=strlen(s+1); for(int i=1;i<=n;++i) insert(s[i]-'a'); for(int i=2;i<=ptot;++i) c[i]=1; inittopo(); for(int i=ptot;i;--i){ int u=a[i];b[u]=c[u]; for(int j=0;j<26;++j) if(son[u].find(j)!=son[u].end()) b[u]+=b[son[u][j]]; } int q;read(q); while(q--){ int now=1,k,l=0;read(k); while(1){ if(k<=c[now]) break; k-=c[now]; for(int j=0;j<26;++j){ if(son[now].find(j)==son[now].end()) continue; if(k<=b[son[now][j]]){ans[++l]=j,now=son[now][j];break;} k-=b[son[now][j]]; } } if(!l){println(-1);continue;} for(int i=1;i<=l;++i) print((char)(ans[i]+'a')); print('\n'); } return 0; }