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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

后缀自动机习题合集

發(fā)布時(shí)間:2025/5/22 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 后缀自动机习题合集 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

(寫的都是初中小朋友czl早就切過(guò)的題……)

http://www.cnblogs.com/Lyush/p/3281546.html

?

POJ-1509?Glass Beads

UVA - 719?Glass Beads

題意:一個(gè)字符串可以將第一個(gè)字符放到最后一位,然后問(wèn)不斷這樣做可以得到的字典序最小的字符串

sam模板題,copy一遍建個(gè)sam,然后直接在sam中跑一遍就行了。

sam記錄了字符串的所有后綴(也隨便記錄了字串),從root開(kāi)始到每個(gè)接受態(tài)節(jié)點(diǎn)都是一個(gè)后綴(或多個(gè)),從root開(kāi)始到每個(gè)節(jié)點(diǎn)都是一個(gè)子串(或多個(gè))。由于copy一遍后把所有的情況的包括進(jìn)去了,那么只要跑len(原長(zhǎng))遍就行了!

constmaxn=30000; varstep,pre:array[0..maxn]of longint;son:array[0..maxn,0..25]of longint;tot,tail,t:longint;procedure add(x:longint); vari,j,k,np,p:longint; beginp:=tail;inc(tot);np:=tot;step[np]:=step[tail]+1;while (p>=0) and (son[p,x]=-1) do beginson[p,x]:=np;p:=pre[p];end;tail:=np;if p<0 then pre[np]:=0elseif step[son[p,x]]=step[p]+1 thenpre[np]:=son[p,x]else beginj:=son[p,x];inc(tot);k:=tot;for i:=0 to 25 do son[k,i]:=son[j,i];step[k]:=step[p]+1;pre[k]:=pre[j];pre[j]:=k;pre[np]:=k;while (p>=0) and (son[p,x]=j) do beginson[p,x]:=k;p:=pre[p];end;end; end;procedure work; vars:ansistring;len,i,j,k,p:longint; beginreadln(s);len:=length(s);s:=s+s;for i:=1 to len<<1 doadd(ord(s[i])-97);p:=0;for i:=1 to len dofor j:=0 to 25 doif son[p,j]>=0 then beginp:=son[p,j];break;end;writeln(step[p]-len+1); end;beginreadln(t);while t>0 do begindec(t);fillchar(pre,sizeof(pre),255);fillchar(son,sizeof(son),255);fillchar(step,sizeof(step),0);tot:=0;tail:=0;work;end end. View Code

?

SPOJ-1811?Longest Common Substring

題意:求兩個(gè)字符串的最長(zhǎng)公共字串。

(似乎做sa的時(shí)候做過(guò)?然后翻出sa的代碼,交上去光榮tle……sam虐殺sa!!)

繼續(xù)貼麗潔姐論文話:

給兩個(gè)長(zhǎng)度小于100000的字符串A和B,求出他們的最長(zhǎng)公共連續(xù)子串。 我們構(gòu)造出A的后綴自動(dòng)機(jī)SAM
對(duì)于SAM的每個(gè)狀態(tài)s,令r為Right(s)中任意的一個(gè)元素,它代表的是結(jié)束位置在r的,長(zhǎng)度在[Min(s),Max(s)]之間的所有子串。
我們不妨對(duì)狀態(tài)s,求出所有B的子串中,從任意r開(kāi)始往前能匹配的最大長(zhǎng)度L,那么min(L,Max(s))就可以更新答案了。 我們考慮用SAM讀入字符串B。 令當(dāng)前狀態(tài)為s,同時(shí)最大匹配長(zhǎng)度為len 我們讀入字符x。如果s有標(biāo)號(hào)為x的邊,
那么s=trans(s,x),len = len+1 否則我們找到s的第一個(gè)祖先a,它有標(biāo)號(hào)為x的邊,令
s=trans(a,x),len=Max(a)+1。 如果沒(méi)有這樣的祖先,那么令s=root,len=0。 在過(guò)程中更新?tīng)顟B(tài)的最大匹配長(zhǎng)度(在這道題中我沒(méi)有理解這句話,直接像以前處理kmp一樣邊跑邊更新,后來(lái)寫多個(gè)串的最長(zhǎng)公共子串時(shí)就因?yàn)檫@個(gè)wa了好久!) 注意到我們求的是對(duì)于任意一個(gè)Right集合中的r,最大的匹配長(zhǎng)度。那么對(duì)于一個(gè)狀態(tài)s,它的結(jié)果自然也可以作為它Parent的結(jié)果,我們可以從底到上更新一遍。 然后問(wèn)題就解決了。 constmaxn=400000; varson:array[0..maxn,0..25]of longint;pre,step:array[0..maxn]of longint;last,tot:longint;function addpoint:longint; vari:longint; begininc(tot);//pre[tot]:=-1;// for i:=0 to 25 do son[tot,i]:=0;exit(tot); end;procedure add(x:longint); vari,new,now,old,more:longint; beginnew:=addpoint;now:=last;step[new]:=step[now]+1;while (now>=0) and (son[now,x]=0) do beginson[now,x]:=new;now:=pre[now];end;last:=new;if now<0 then pre[new]:=0elseif step[son[now,x]]=step[now]+1 thenpre[new]:=son[now,x]else beginold:=son[now,x];more:=addpoint;for i:=0 to 25 do son[more,i]:=son[old,i];step[more]:=step[now]+1;pre[more]:=pre[old];pre[old]:=more;pre[new]:=more;while (now>=0) and (son[now,x]=old) do beginson[now,x]:=more;now:=pre[now];end;end; end;procedure work; vars:ansistring;now,max,long,i,j:longint; beginfillchar(pre,sizeof(pre),255);readln(s);for i:=1 to length(s) do add(ord(s[i])-97);readln(s);now:=0;max:=0;long:=0;for i:=1 to length(s) do beginj:=ord(s[i])-97;if son[now,j]<>0 then begininc(long);now:=son[now,j];endelse beginwhile (now>=0) and (son[now,j]=0) do now:=pre[now];if now<0 then beginlong:=0;now:=0;endelse beginlong:=step[now]+1;now:=son[now,j];end;end;if long>max then max:=long;end;writeln(max); end;beginwork; end. View Code

?

SPOJ-1812?Longest Common Substring II

題意:求多個(gè)字符串的最長(zhǎng)公共字串。

還是以第一個(gè)字符串建個(gè)sam。然后其他字符串像上一道一樣跑sam。

那么狀態(tài)s,其他串對(duì)它的匹配長(zhǎng)度分別是a1,a2,a3……an的話,狀態(tài)s的最長(zhǎng)公共字符串就是min(a1,a2,a3……an,max(s))。

然后去最長(zhǎng)的狀態(tài)就行了!

constmaxn=200033;varp,num,step,ans,pre:array[0..maxn]of longint;son:array[0..maxn,0..25]of longint;tot,last:longint;function max(x,y:longint):longint; beginif x<y then exit(y);exit(x); end;function min(x,y:longint):longint; beginif x<y then exit(x);exit(y); end;procedure add(x:longint); vari,now,new,more,old:longint; begininc(tot);new:=tot;now:=last;last:=new;step[new]:=step[now]+1;while (now>=0) and (son[now,x]=0) do beginson[now,x]:=new;now:=pre[now];end;if now<0 then pre[new]:=0else beginold:=son[now,x];if step[now]+1=step[old] then pre[new]:=oldelse begininc(tot);more:=tot;for i:=0 to 25 do son[more,i]:=son[old,i];step[more]:=step[now]+1;pre[more]:=pre[old];pre[old]:=more;pre[new]:=more;while (now>=0) and (son[now,x]=old) do beginson[now,x]:=more;now:=pre[now];end;end;end; end;procedure into; vars:ansistring;i,len:longint; begintot:=0;pre[0]:=-1;readln(s);len:=length(s);for i:=1 to len doadd(ord(s[i])-97);fillchar(num,sizeof(num),0);for i:=1 to tot do inc(num[step[i]]);for i:=1 to len do inc(num[i],num[i-1]);for i:=1 to tot do beginp[num[step[i]]]:=i;dec(num[step[i]]);end;for i:=1 to tot do beginnum[i]:=0;ans[i]:=step[p[i]];end; end;procedure work; vars:ansistring;i,j,now,long,x,answer,n:longint; beginwhile not eof do beginreadln(s);now:=0;long:=0;for i:=1 to length(s) do beginj:=ord(s[i])-97;if son[now,j]<>0 then beginnow:=son[now,j];inc(long);num[now]:=max(num[now],long);endelse beginwhile (now>=0) and (son[now,j]=0) do now:=pre[now];if now<0 then beginnow:=0;long:=0;endelse beginlong:=step[now]+1;now:=son[now,j];num[now]:=max(num[now],long);end;end;end;for i:=tot downto 1 do beginx:=p[i];step[x]:=min(step[x],num[x]);num[pre[x]]:=max(num[pre[x]],num[x]);num[x]:=0;end;end;answer:=0;for i:=1 to tot doif answer<step[i] then answer:=step[i];writeln(answer); end;begininto;work; end. View Code

?

?

SPOJ-8222?Substrings

題意:給一個(gè)字符串s,求長(zhǎng)度為i(i屬于【1,len】)的出現(xiàn)次數(shù)最多的子串出現(xiàn)的次數(shù)(好繞)……

上一篇有提到子串出現(xiàn)的個(gè)數(shù)就是right集合的大小。

那么用那個(gè)方法就行了(其實(shí)不用dfs序,可以用拓?fù)浜屯芭?#xff0c;拓?fù)湟_(kāi)多幾個(gè)數(shù)組,桶排不用……速度沒(méi)比過(guò))

注意right樹(shù)中要用兒子更新父親,就是長(zhǎng)度為i+1可以更新長(zhǎng)度為i的值……

typearr=recordfrom,next:longint;end; constmaxn=600000; varedge:array[0..maxn]of arr;ans,step,first,sum,num,pre,p:array[0..maxn]of longint;son:array[0..maxn,0..25]of longint;tot,last,len,esum:longint;function max(x,y:longint):longint; beginif x>y then exit(x);exit(y); end;function addpoint:longint; begininc(tot);exit(tot); end;procedure addedge(j,k:longint); begininc(esum);edge[esum].from:=j;edge[esum].next:=first[k];first[k]:=esum;inc(num[j]); end;procedure add(x:longint); varnow,new,more,old,i:longint; beginnew:=addpoint;now:=last;step[new]:=step[now]+1;while (now>=0) and (son[now,x]=0) do beginson[now,x]:=new;now:=pre[now];end;last:=new;if now<0 then pre[now]:=0else beginold:=son[now,x];if step[old]=step[now]+1 thenpre[new]:=oldelse beginmore:=addpoint;for i:=0 to 25 do son[more,i]:=son[old,i];step[more]:=step[now]+1;pre[more]:=pre[old];pre[new]:=more;pre[old]:=more;while (now>=0) and (son[now,x]=old) do beginson[now,x]:=more;now:=pre[now];end;end;end; end;procedure into; vars:ansistring;i,j:longint; beginreadln(s);pre[0]:=-1;last:=0;len:=length(s);for i:=1 to len do add(ord(s[i])-97);for i:=1 to tot dofor j:=0 to 25 doif son[i,j]<>0 then addedge(i,son[i,j]); end;procedure work; varhead,tail,i,x,fa:longint; beginhead:=1;tail:=0;while last>=0 do beginsum[last]:=1;last:=pre[last];end;for i:=0 to tot doif num[i]=0 then begininc(tail);p[tail]:=i;end;while head<=tail do beginx:=p[head];i:=first[x];while i>0 do beginfa:=edge[i].from;inc(sum[fa],sum[x]);dec(num[fa]);if num[fa]=0 then begininc(tail);p[tail]:=fa;end;i:=edge[i].next;end;inc(head);end;for i:=1 to tot doans[step[i]]:=max(ans[step[i]],sum[i]);for i:=len-1 downto 1 doans[i]:=max(ans[i],ans[i+1]);for i:=1 to len dowriteln(ans[i]); end;begininto;work; end. View Code

?

SPOJ-7258?Lexicographical Substring Search

題意:給定一個(gè)字符串,取出所有的子串按照字典序排序并去重后,求第K大的子串。

先預(yù)處理出每個(gè)節(jié)點(diǎn)的所包含子串總數(shù),然后對(duì)每個(gè)詢問(wèn)在sam上爬一爬就行了!

由于spoj卡得緊,處理詢問(wèn)的時(shí)候不能從0-25都掃一遍,要先記錄兒子的數(shù)量,具體看代碼吧。

constmaxn=200000;varstep,num,sum,pre,p:array[0..maxn]of longint;col,too,son:array[0..maxn,0..25]of longint;last,tot:longint;procedure add(x:longint); vari,new,now,more,old:longint; begininc(tot);new:=tot;now:=last;step[new]:=step[now]+1;last:=new;while (now>=0) and (son[now,x]=0)do beginson[now,x]:=new;now:=pre[now];end;if now<0 then pre[new]:=0else beginold:=son[now,x];if step[old]=step[now]+1 then pre[new]:=oldelse begininc(tot);more:=tot;for i:=0 to 25 do son[more,i]:=son[old,i];step[more]:=step[now]+1;pre[more]:=pre[old];pre[new]:=more;pre[old]:=more;while (now>=0) and (son[now,x]=old) do beginson[now,x]:=more;now:=pre[now];end;end;end; end;procedure into; vars:ansistring;i,j,x,len:longint; beginpre[0]:=-1;last:=0;tot:=0;readln(s);len:=length(s);for i:=1 to len do add(ord(s[i])-97);fillchar(num,sizeof(num),0);for i:=1 to tot do beginsum[i]:=1;inc(num[step[i]]);end;for i:=2 to len do inc(num[i],num[i-1]);for i:=1 to tot do beginp[num[step[i]]]:=i;dec(num[step[i]]);end;fillchar(num,sizeof(num),0);for i:=tot downto 0 do beginx:=p[i];for j:=0 to 25 doif son[x,j]<>0 then begininc(num[x]);col[x,num[x]]:=j;too[x,num[x]]:=son[x,j];inc(sum[x],sum[son[x,j]]);end;end;//for i:=0 to tot do writeln(sum[i]); end;procedure work; varq,n,i,k,now:longint;answer:ansistring; beginreadln(q);while q>0 do begindec(q);readln(n);answer:='';now:=0;while n>0 do beginfor i:=1 to num[now] do begink:=too[now,i];if sum[k]<n thendec(n,sum[k])else begindec(n);answer:=answer+chr(97+col[now,i]);now:=k;break;end;end;end;writeln(answer);end; end;begininto;work end. View Code

?

HDU-4622?Reincarnation

題意:給定一個(gè)字符串,多組詢問(wèn),每個(gè)詢問(wèn)給一個(gè)區(qū)間,求出該區(qū)間內(nèi)共有多少個(gè)不同的子串。

如果是單個(gè)子串好處理&(sa和sam都可以嘛)。

但是現(xiàn)在要求區(qū)間。我們可以這樣考慮,每次按左端點(diǎn)以此往右端點(diǎn)建。比如當(dāng)前是【l,r】然后變成【l,r+1】的話,就是sam(【l,r】)變成sam(【l,r+1】)。多出的子串就是step【last】-step【pre【last】】(這個(gè)很重要,在統(tǒng)計(jì)時(shí)經(jīng)常用到這個(gè)式子)

然后就直接處理出所有區(qū)間就行了……(暴力到不敢相信)

constmaxn=5000; varans:array[0..2100,0..2100]of longint;pre,step:array[0..maxn]of longint;son:array[0..maxn,0..25]of longint;tot,last,t,n,len,i,j:longint;s:ansistring;function addpoint:longint; begininc(tot);pre[tot]:=-1;fillchar(son[tot],sizeof(son[tot]),0);addpoint:=tot end;procedure add(x:longint); vari,now,new,old,more:longint; beginnew:=addpoint;now:=last;last:=new;step[new]:=step[now]+1;while (now>=0) and (son[now,x]=0) do beginson[now,x]:=new;now:=pre[now];end;if now<0 then pre[new]:=0else beginold:=son[now,x];if step[old]=step[now]+1 then pre[new]:=oldelse beginmore:=addpoint;for i:=0 to 25 do son[more,i]:=son[old,i];step[more]:=step[now]+1;pre[more]:=pre[old];pre[old]:=more;pre[new]:=more;while (now>=0) and (son[now,x]=old) do beginson[now,x]:=more;now:=pre[now];end;end;end end;beginreadln(t);while t>0 do begindec(t);readln(s);len:=length(s);for i:=1 to len do begintot:=-1;last:=addpoint;ans[i,i-1]:=0;for j:=i to len do beginadd(ord(s[j])-97);ans[i,j]:=ans[i,j-1]+step[last]-step[pre[last]];end;end;readln(n);while n>0 do begindec(n);readln(i,j);writeln(ans[i,j]);end;end end. View Code

(當(dāng)然也可以快排詢問(wèn),我懶所以沒(méi)有做)

?

HDU-4641?K-string

題意:給定字符串,有m次操作,每次操作可以向該字符串末尾添加一個(gè)字符或者詢問(wèn)在字符串中出現(xiàn)了至少K次的子串一共有多少個(gè)?

就是在插入字符后順便統(tǒng)計(jì)一下就行了,如果這個(gè)點(diǎn)出現(xiàn)次數(shù)大于k那么一定已經(jīng)在ans中了。

要注意的是在step【old】>step【now】+1時(shí)復(fù)制點(diǎn)時(shí),出現(xiàn)次數(shù)要也一起復(fù)制過(guò)去……

constmaxn=500000; varstep,num,pre:array[0..maxn]of longint;son:array[0..maxn,0..25]of longint;ans,tot,last,n,m,kk,i,j:longint;ch:char;s:ansistring;function addpoint:longint; vari:longint; begininc(tot);pre[tot]:=-1;step[tot]:=0;num[tot]:=0;for i:=0 to 25 doson[tot,i]:=0;addpoint:=tot; end;procedure add(x:longint); vari,now,new,more,old:longint; beginnew:=addpoint;now:=last;last:=new;step[new]:=step[now]+1;while (now>=0) and (son[now,x]=0) do beginson[now,x]:=new;now:=pre[now];end;if now<0 then pre[new]:=0else beginold:=son[now,x];if step[old]=step[now]+1 then pre[new]:=oldelse beginmore:=addpoint;for i:=0 to 25 do son[more,i]:=son[old,i];step[more]:=step[now]+1;num[more]:=num[old];pre[more]:=pre[old];pre[old]:=more;pre[new]:=more;while (now>=0) and (son[now,x]=old) do beginson[now,x]:=more;now:=pre[now];end;end;end;now:=last;while (now>0) and (num[now]<kk) do begininc(num[now]);if num[now]=kk thenans:=ans+step[now]-step[pre[now]];now:=pre[now];end; end;beginwhile not eof do beginreadln(n,m,kk);tot:=-1;last:=addpoint;ans:=0;readln(s);for i:=1 to length(s) doadd(ord(s[i])-97);while m>0 do begindec(m);read(j);if j=1 then beginread(ch);read(ch);add(ord(ch)-97);{for i:=0 to tot do beginwrite(i,':');for j:=0 to 25 dowrite(son[i,j],' ');writeln;end; }endelsewriteln(ans);readln;end;end end. View Code

?

待填之坑

SPOJ-8747. Substrings II && BZOJ-2555: SubString ( Suffix Automaton + Link Cut Tree )/BZOJ 2555 Substring (要lct嚇傻)

BZOJ 3238 AHOI2013 差異 后綴自動(dòng)機(jī)

BZOJ 2882 工藝 后綴自動(dòng)機(jī)

?

2015.04.14……看看人家學(xué)習(xí)的深度……唉,還是太弱了?http://www.cnblogs.com/zyfzyf/p/4397216.html#3161819

轉(zhuǎn)載于:https://www.cnblogs.com/Macaulish/p/4296557.html

總結(jié)

以上是生活随笔為你收集整理的后缀自动机习题合集的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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