Bzoj3998 弦论

物理题目传送门

求第k大的子串?SAM模板题啊

CLJ的论文都讲了怎么做啊,把自动机看成一个后缀Trie求出size让后像多叉平衡树那样乱搞就好了~

比前两个哈希的题好多了~ (顺便,hdu高亮好好看啊)

#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 1000010
using namespace std;
char c[N];
int s[N][26],mx[N],sz[N],f[N];
int n,m,T,k,cnt=1,lst=1,v[N],r[N],w[N];
inline int extend(int c){
    int p=lst,np=lst=++cnt,q,nq;
    mx[np]=mx[p]+1; sz[np]=1;
    for(;p&&!s[p][c];p=f[p]) s[p][c]=np;
    if(!p) return f[np]=1;
    q=s[p][c];
    if(mx[q]==mx[p]+1) f[np]=q;
    else{
        nq=++cnt;
        mx[nq]=mx[p]+1;
        f[nq]=f[q]; f[q]=f[np]=nq;
        memcpy(s[nq],s[q],26<<2);
        for(;p&&s[p][c]==q;p=f[p]) s[p][c]=nq;
    }
}
inline void dfs(int x){
    if(k<=sz[x]) return; else k-=sz[x];
    for(int j=0;j<26;++j)
        if(k>w[s[x][j]])k-=w[s[x][j]];
        else { putchar(j+'a'); dfs(s[x][j]); break; }
}
int main(){
    scanf("%s%d%d",c+1,&T,&k); n=strlen(c+1);
    for(int i=1;i<=n;++i) extend(c[i]-'a');
    for(int i=1;i<=cnt;++i) ++v[mx[i]];
    for(int i=1;i<=n;++i) v[i]+=v[i-1];
    for(int i=cnt;i;--i) r[v[mx[i]]--]=i;
    if(T) for(int i=cnt;i;--i) sz[f[r[i]]]+=sz[r[i]];
    else  for(int i=cnt;i;--i) sz[i]=1; sz[1]=*sz=0; memcpy(w,sz,sizeof w);
    for(int i=cnt;i;--i) for(int j=0;j<26;++j) w[r[i]]+=w[s[r[i]][j]];
    if(k>w[1]) puts("-1"); else dfs(1);
}

原文地址:https://www.cnblogs.com/Extended-Ash/p/8312606.html