部落格觀賞效果更佳
你以為我只是單純的子串行自動機嗎?其實我是是子串行自動機+可持久化陣列噠!
但是我看見乙個大神給出了乙個特別神仙又巧妙的思路!我不禁要寫一篇題解記錄下這神奇的思路!
而且**賊短哦~比可持久化陣列好寫到不知道多少倍呢www
給定乙個序列a
aa長度<=1e5,還要一些要詢問的字串b
bb,長度和<=1
e6
<=1e6
<=1
e6。對於每個b
bb,詢問其是否是a
aa的子串行。序列中的每個值都在1e5
1e51e
5以內。
在暴力匹配子串行的時候,用鍊錶(或者vector)記錄哪些詢問的答案會被更新即珂。複雜度o(1
e6+1
e5
)o(1e6+1e5)
o(1e6+
1e5)
。正片開始。我們知道,樸素的子串行的查詢是o(∣
a∣×∣
b∣
)o(|a|\times |b|)
o(∣a∣×
∣b∣)
的。我們大約是這樣寫的:
int p=1;
f(i,1,
|a|)
if(a[i]
==b[p]
)++p;
然後判斷是否p==|b|。其中p
pp表示我們當前匹配到了哪乙個位置。
子串行自動機:設nxt
[i][
j]
nxt[i][j]
nxt[i]
[j]表示i
ii往後第乙個值為j
jj的出現在哪乙個位置。這樣的確方便查詢,但是這裡值域1e5
1e51e
5,這個做法顯然沒救了。
考慮優化第乙個方法:把所有的詢問放到一塊來處理。那麼,當我們找到乙個a[i]的時候,所有滿足b[p]==a[i]的p都會執行p++操作。
那麼我們只要記錄所有b[p]==a[i]的b[p]都在哪些位置就好了。所以,首先要用乙個鍊錶(鏈式前向星),把b
bb的值按輸入順序串起來。然後要用乙個鍊錶把b
bb按值域分類。具體的,記hea
d[i]
head[i]
head[i
]表示b
bb中值為i
ii的數最後乙個出現的位置,nxt
[i
]nxt[i]
nxt[i]
表示b
bb中前乙個和b[i
]b[i]
b[i]
相同的。然後我們令cur
=hea
d[xx
x]
cur=head[***]
cur=he
ad[x
xx],不斷的令cur
=nxt
[cur
]cur=nxt[cur]
cur=nx
t[cu
r],就珂以找到b
bb中所有值為xxx
***xx
x的位置了。
然後,我們在把b
bb按輸入順序穿起來的時候,對於每個b
bb的最後乙個字元,我們令它的下乙個值為−i-i
−i,其中i
ii為這個b
bb在輸入中的編號。這樣,
「既判定了匹配到了末尾,又判定了當前所在的字串(的編號,博主注),可謂一舉兩得~」(作者原話)關於如何處理詢問:
我們以a
aa為基準,不斷在b
bb中找到匹配。對於每個a[i
]a[i]
a[i]
,我們通過遍歷前向星找到b
bb中值為a[i
]a[i]
a[i]
的位置。如果這個位置是最後乙個位置,那麼這個b
bb就匹配成功,我們標記它是a
aa的子串行。否則,我們把原來的指標指向b[i
]b[i]
b[i]
的刪掉,連線上b[i
+1
]b[i+1]
b[i+1]
,就是實現上面的p++
p++p+
+操作。
然後我們發現,如果匹配成功了,也要刪掉指標。那就不如在遍歷到a[i
]a[i]
a[i]
的時候,直接全部清空好了。(鏈式前向星清空很簡單,只要令hea
d[a[
i]]=
0head[a[i]]=0
head[a
[i]]
=0即珂。)
#include
using
namespace std;
namespace flandre_scarlet
int type,n,q,m;
//type:沒什麼用,給你騙分用的。滿分的**是不需要騙分的。
int a[n]
;void
input()
int len[n]
,nxtb[n]
,valb[n]
,cntb;
//按輸入順序記錄b的鍊錶們www
//len[i]: 第i個詢問中b的長度
//nxtb[i]: 用來把b串起來。記錄下標。一般nxt[i]=i+1。如果i到末尾了,那麼nxtb[i]=-id。
//id為這個b的編號。這一步的妙處上面說了
//valb[i]: 和nxtb區別,這個是記錄b的值。
//cntb: 總共有多少個點。到最後,它的值就等於len[i]的和。
int node[n]
,head[n]
,nxt[n]
,cntval;
//按b的值域分類記錄的鍊錶們www
//node[i]: 記錄點在b中的編號,方便求出nxtb
//head[i]: 記錄b中最後乙個值為i的位置(這邊的位置是在鍊錶中的位置,而不是b中的位置)。
//nxt[i]: 記錄b中下乙個和i的值相同的位置。
bool cxk[n]
;//cxk[i]: 第i個詢問是否是子串行
void
add(
int u,
int v)
//b中值為u的位置新增上乙個v
void
soviet()
nxtb[cntb]
=-i;
//好東西,上面講了}f
(i,1
,n)}
f(i,
1,q)
}#define flan void
flan ismywife()
}int
main()
Subsequence(序列自動機模板題)
題目大意 給你乙個字串,然後再給你m個字串,然後問你在第乙個字串中不連續的子串能不能構成輸入的子串。具體思路 構建乙個序列自動機就可以了。剛接觸,記錄下 ac 1 include2 using namespace std 3 define ll long long 4 define inf 0x3f...
序列自動機 模板
南昌邀請賽網路賽m題 subsequence 題意 給你乙個字串s,長度小於1e5,然後n次詢問,n小於1e5,每次輸入乙個字串t,問t是不是s的子串行。t長度小於1000 input abcdefg 3abc adgcba output yes yesno 思路 序列自動機其實就是先預處理出來乙個...
序列自動機模板
題意 有乙個字串s1,現在給你n個字串s2,每次你需要回答s2是否是s1的子串行。解題心得 序列自動機其實就是先預處理出來乙個陣列,next i j 表示在位置 i 的後面第乙個字元 j 所在的位置,預處理出next陣列的複雜度就是log n 26 每次詢問就是log m 的複雜度 m是每次詢問字串...