Luogu P3975 [TJOI2015]弦论

本质不同的第 \(k\) 小:每个点的初始权值为 \(1\)

只区分位置的第 \(k\) 小:每个点的初始权值为 \(|{\rm endpos}|\) ,表示出现的次数。

然后进行拓扑排序。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=1000010;
int n,t,k,lst=1,tot=1,cnt;
int len[N],fa[N],c[N][26],sz[N],d[N],mem[N],f[N];
char s[N>>1];
int vr[N<<1],nxt[N<<1],fir[N];
inline void add(int u,int v) 
  {vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void add(int ch) {
  R p=lst,np=lst=++tot;
  sz[tot]=1;
  len[np]=len[p]+1;
  for(;p&&!c[p][ch];p=fa[p]) c[p][ch]=np;
  if(!p) fa[np]=1;
  else {
    R q=c[p][ch];
    if(len[q]==len[p]+1) fa[np]=q;
    else {
      R nq=++tot;
      memcpy(c[nq],c[q],26<<2);
      fa[nq]=fa[q],len[nq]=len[p]+1;
      fa[np]=fa[q]=nq;
      for(;p&&c[p][ch]==q;p=fa[p]) c[p][ch]=nq;
    }
  }
}
inline void solve() {
  R p=1;
  while(k) {
    for(R i=0;i<26;++i) if(c[p][i]) {
      if(k>f[c[p][i]]) k-=f[c[p][i]];
      else {
        putchar(i+'a');
        p=c[p][i];
        k-=sz[p]; break;
      }
    }
  } putchar(10);
}
inline void main() {
  scanf("%s",s+1);
  t=g(),k=g(),n=strlen(s+1);
  for(R i=1;i<=n;++i) add(s[i]-'a');
  for(R i=1;i<=tot;++i) ++d[len[i]];
  for(R i=1;i<=n;++i) d[i]+=d[i-1];
  for(R i=1;i<=tot;++i) mem[d[len[i]]--]=i;
  if(!t) for(R i=1;i<=tot;++i) sz[i]=1;
  else for(R i=tot;i;--i) 
    sz[fa[mem[i]]]+=sz[mem[i]];;
  //sz[u]是
  //t==0: 1,表示每个点初始有个空串。
  //t==1: parent树的子树和,即 |endpos|
  //f[u]是
  //t==0: 子串个数
  //t==1: \sum 每个串的出现次数(相当于是带权的)
  sz[1]=0;
  for(R i=tot;i;--i) {
    R u=mem[i];
    f[u]=sz[u];
    for(R j=0;j<26;++j) if(c[u][j])
      f[u]+=f[c[u][j]];
  } 
  if(k>f[1]) puts("-1");
  else solve();
}
} signed main() {Luitaryi::main(); return 0;}

2020.01.09

posted @ 2020-01-10 17:49  LuitaryiJack  阅读(82)  评论(0编辑  收藏  举报