BZOJ3998: [TJOI2015]弦论

来源:互联网 发布:产品经理 人工智能 编辑:程序博客网 时间:2024/06/03 22:06

听说是后缀自动机裸题?
深度理解一下SAM就会发现,可重复的话,每个np的初始值是1然后自底向上拓扑排序一遍,就得到了每个节点代表的字串出现的次数。不可重复的话,每个节点的val是1即可。
对于tr[i].sum=∑tr[ tr[i].nxt[j] ].sum即可,sum数组搞出来就26分得了233…

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>//by:MirrorGrayusing namespace std;const int N=1111111;int T,K;int cnt,last,root,n,gs[N],q[N];char s[N]; struct node{    int nxt[26],fa,mx,sum,val;}tr[N];int nwn(int l){    tr[++cnt].mx=l;    return cnt;}int extend(int x){    int np=nwn(tr[last].mx+1);tr[np].val=1;    int p=last;last=np;    for(;p && !tr[p].nxt[x];p=tr[p].fa)tr[p].nxt[x]=np;    if(p==0)return tr[np].fa=root,233;    int q=tr[p].nxt[x];    if(tr[q].mx==tr[p].mx+1)return tr[np].fa=q,233;    int nq=nwn(tr[p].mx+1);    tr[nq].fa=tr[q].fa;tr[q].fa=tr[np].fa=nq;    memcpy(tr[nq].nxt,tr[q].nxt,sizeof(tr[q].nxt));    for(;p && tr[p].nxt[x]==q;p=tr[p].fa)tr[p].nxt[x]=nq;    return 233;}void toposort(){    for(int i=1;i<=n;i++)gs[i]=0;    for(int i=1;i<=cnt;i++)gs[ tr[i].mx ]++;    for(int i=1;i<=n;i++)gs[i]+=gs[i-1];    for(int i=cnt;i;i--)q[ gs[ tr[i].mx ]-- ]=i;    if(T==1)for(int i=cnt;i;i--)tr[ tr[q[i]].fa ].val+=tr[ q[i] ].val;    else for(int i=cnt;i;i--)tr[ tr[q[i]].fa ].val=1;    tr[root].val=0;    for(int i=cnt;i;i--){        tr[ q[i] ].sum=tr[ q[i] ].val;        for(int j=0;j<26;j++)        tr[ q[i] ].sum+=tr[ tr[q[i]].nxt[j] ].sum;    }}int dfs(int x,int k){    if(k<=tr[x].val)return 233;    k-=tr[x].val;    for(int i=0;i<26;i++){        if(k<=tr[ tr[x].nxt[i] ].sum)return putchar(i+'a'),dfs(tr[x].nxt[i],k);        k-=tr[ tr[x].nxt[i] ].sum;    }    return 233;}int main(){    scanf("%s%d%d",s,&T,&K);n=strlen(s);    last=root=nwn(0);    for(int i=0;s[i];i++)extend(s[i]-'a');    toposort();    if(K>tr[root].sum)puts("-1");    else dfs(root,K);    return 0;}
0 0