日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

【bzoj4566】[Haoi2016]找相同字符【后缀自动机】

發(fā)布時(shí)間:2023/12/18 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【bzoj4566】[Haoi2016]找相同字符【后缀自动机】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目傳送門
題解:在文本串上建后綴自動(dòng)機(jī),用模式串在后綴自動(dòng)機(jī)上跑。掃一遍模式串,在后綴自動(dòng)機(jī)上走,走不了就跳fail再走。
走的過程中,維護(hù)模式串與文本串匹配的最大長(zhǎng)度,并且統(tǒng)計(jì)答案。
怎么統(tǒng)計(jì)答案呢?
我們知道,狀態(tài)x表示的字符串的長(zhǎng)度為len[x]len[x],對(duì)應(yīng)了len[x]?len[fail[x]]len[x]?len[fail[x]]個(gè)子串(每個(gè)子串都是當(dāng)前狀態(tài)的前綴)。因此,狀態(tài)x表示的子串總數(shù)為(len[x]?len[fail[x]])?cnt[x](len[x]?len[fail[x]])?cnt[x]。同時(shí),狀態(tài)x的fail一定是x表示字符串的后綴。因此,如果當(dāng)前在后綴自動(dòng)機(jī)上走到了狀態(tài)x,最大匹配長(zhǎng)度為maxl,就把答案加上x沿fail到根節(jié)點(diǎn)上所有狀態(tài)表示的子串總數(shù)。注意x這個(gè)狀態(tài)是特殊的,它與模式串做能匹配的子串個(gè)數(shù)是(maxl?len[fail[x]])?cnt[x](maxl?len[fail[x]])?cnt[x]。其他跳fail到根節(jié)點(diǎn)路徑上的狀態(tài)則直接加上其表示的子串總數(shù),因?yàn)檫@些狀態(tài)是與模式串完全匹配的。(難以描述,自行理解一下吧)
具體實(shí)現(xiàn)詳見代碼。

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N=200005; int l1,l2,a[N*2]; ll ans=0; char s1[N],s2[N]; struct SAM{int last,tot,len[N*2],fail[N*2],cnt[N*2],ch[N*2][26],c[N*2];SAM(){last=tot=1;}void insert(int x){int p=last,np=++tot;len[np]=len[p]+1;last=np;for(;p&&!ch[p][x];p=fail[p]){ch[p][x]=np;}if(!p){fail[np]=1;}else{int q=ch[p][x];if(len[q]==len[p]+1){fail[np]=q;}else{int nq=++tot;len[nq]=len[p]+1;memcpy(ch[nq],ch[q],sizeof(ch[q]));fail[nq]=fail[q];fail[q]=fail[np]=nq;for(;p&&ch[p][x]==q;p=fail[p]){ch[p][x]=nq;}}}cnt[np]=1;}void init(){for(int i=1;i<=tot;i++){c[len[i]]++;}for(int i=1;i<=l1;i++){c[i]+=c[i-1];}for(int i=1;i<=tot;i++){a[c[len[i]]--]=i;}for(int i=tot;i>=1;i--){cnt[fail[a[i]]]+=cnt[a[i]];}}void get(int now,int l){while(len[fail[now]]>l){now=fail[now];}while(fail[now]){ans+=1LL*cnt[now]*(l-len[fail[now]]);l=len[fail[now]];now=fail[now];}} }sam; int main(){scanf("%s%s",s1,s2);l1=strlen(s1);l2=strlen(s2);for(int i=0;i<l1;i++){sam.insert(s1[i]-'a');}sam.init();int now=1,len=0;for(int i=0;i<l2;i++){while(now&&!sam.ch[now][s2[i]-'a']){now=sam.fail[now];}if(!now){now=1;len=0;}else{len=min(len,sam.len[now])+1;now=sam.ch[now][s2[i]-'a'];}sam.get(now,len);}printf("%lld\n",ans);return 0; }

轉(zhuǎn)載于:https://www.cnblogs.com/2016gdgzoi471/p/9476890.html

總結(jié)

以上是生活随笔為你收集整理的【bzoj4566】[Haoi2016]找相同字符【后缀自动机】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。