jzoj4025-找回密码【后缀自动机】
生活随笔
收集整理的這篇文章主要介紹了
jzoj4025-找回密码【后缀自动机】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
大意
一個字符串,要求第k小的子串。
解題思路
先建立一個后綴自動機,然后用一個numinum_inumi?表示第iii個節點的可以到達的點所表示的子串總和,然后從第1號點開始查找,判斷一下找到第k小所在的節點后,然后查找輸出。
代碼
#include<cstdio> #include<algorithm> #include<cstring> #define N 200010 #define Get(W) W>='a'?W-71:W-'A' #define fuGet(W) W>=26?W+71:W+'A' using namespace std; int l,last,fail[N],next[N][56],tot,len[N],num[N]; int ls[N],v[N],head,tail,q[N]; long long sum; char s[100001]; int New(int x,int y){next[x][y]=++tot;len[tot]=len[x]+1; } void bfs() {head=0;q[1]=1;tail=1;v[1]=1;do{int x=q[++head];for (int i=0;i<52;i++)if (next[x][i]&&!v[next[x][i]]){v[next[x][i]]=1;q[++tail]=next[x][i];//建立順序}}while (head<tail);for (;tail;tail--){int x=q[tail];for (int i=0;i<52;i++)if (next[x][i]){ls[x]=i;num[x]+=num[next[x][i]]+1;//按順序計算答案}} } void Get_answer() {int x=1;while (sum){if (!ls[x]&&!next[x][0])break;for (int i=0;i<=ls[x];i++)if (next[x][i]){if (num[next[x][i]]+1>=sum||i==ls[x])//在當前節點的搜索樹中{printf("%c",fuGet(i));int y=next[x][i];sum--;if (sum) x=y;//進入該節點break;}else sum-=num[next[x][i]]+1;//跳轉下一棵}} } int main() {scanf("%s",s);scanf("%lld",&sum);l=strlen(s);last=1;len[1]=0;fail[1]=0;tot=1;for (int i=0;i<l;i++){int addc=Get(s[i]);int k=last,j=0;New(last,addc);//新建節點last=tot;for (j=fail[k];j;j=fail[j])if (!next[j][addc])next[j][addc]=last;//直接連接else{int z=next[j][addc];if (len[z]==len[j]+1)fail[last]=z;//連接else{New(j,addc);for (int l=0;l<52;l++)next[tot][l]=next[z][l];//繼承指針fail[tot]=fail[z];fail[z]=fail[last]=tot;//繼承for (int l=j;l;l=fail[l])if (next[l][addc]==z) next[l][addc]=tot;//繼承連接}break;}if (!j) fail[last]=1;/特判}bfs();//計算numGet_answer(); }總結
以上是生活随笔為你收集整理的jzoj4025-找回密码【后缀自动机】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 英睿达发布新款 T500 PCIe 4.
- 下一篇: 怎样微信投票如何用电脑给微信投票