字首函式,AC自動機

2021-10-10 18:32:20 字數 3447 閱讀 9507

字首函式的應用。

題目大意:我們都知道字首函式,但現在要求求出乙個更強大num陣列一一對於字串s的前i個字元構成的子串,既是它的字尾同時又是它的字首,並且該字尾與該字首不重疊,將這種字串的數量記作num[i]。

​ 其實只要找出最長符合要求字首即可,更短的一定是最長符合要求字首的字首,推字首函式時求乙個「字首」和就好(即累加到最長字首上)。如何求最長不重合既是字首又是字尾的串呢?字首函式求的會包含重合的,想一想最開始重合那個過程,在i-1的位置如i=7,在i=6的位置p[i]一定等於3,這樣i=7時才可能重合,重合時我們只需令j=p

[j−1

]j=p[j-1]

j=p[j−

1]即可。其他過程和求字首函式一樣,注意j設在外面,每次只用從上一次匹配的位置匹配,這樣每次重合也最多重合乙個字元,跳一會p[j-1]即可.

(啊,寫出來好不清晰,如果掌握了字首函式,這個還是可以想到的,至少最直觀可以想到一直跳p[j-1]至不重合,用倍增處理可以降低時間複雜度,然而還是80,看題解有用倍增過的,還只是改了陣列一維和二維的位置,好神奇。

#includeusing namespace std;

const int maxn=1e6+5;

const int mod=1e9+7;

typedef long long ll;

int p[maxn],z[maxn],np[maxn],num[maxn],f[maxn][21];

char s[maxn];

void getpi(int n)

}if(j)

j=f[j][0];*/

if(j)

np[i]=1+num[j-1];

else np[i]=0;

}ll ans=1;

for(int i=0;i​ 寫了一遍忘儲存了!

​ 利用字首函式來容斥。要點:字串雜湊,把字串所有字尾用map儲存並對應好個數,那麼列舉所有字串所有字首,計算對應個數,對應該字首其長度為其字首函式的字首也統計過,但此時他們已不是最長,減去對應個數。

#includeusing namespace std;

typedef long long ll;

typedef unsigned long long ull;

const int mod1=998244353;

//const ll mod2=1222827239;

const int x=2333;

const int maxn=1e5+5;

unordered_mapop;

int id(char c)

ull hx[maxn*10];

ull tx[maxn*10];

void getsufhx(char* s)

int d[maxn][105][105][4];

void init()

void insert(char *s,int v)

void init()//啊啊啊,一定要呼叫一下

void insert(char *s,int v)

^ans[0][i]

i=0∑n​

ans[

0][i

]即為答案。

#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;

using namespace std;

const int maxn=100+5;

const int mod=1e5;

const int sigma_size=4;

int ch[maxn][sigma_size],val[maxn],sz;

int mp[maxn][maxn];

int idx(char c)

void init()//啊啊啊,一定要呼叫一下

void insert(char *s,int v)

}int main()

getfail();

for(int i=0;i<=sz;i++)

if(val[i])

}/*for(int i=0;i<=sz;i++)

printf("\n");

}*/martrix_pow(mp,ans,n,sz,mod);

int res=0;

for(int i=0;i<=sz;i++)//肯定從根出發啊

printf("%d\n",res);

return 0;

}

題目大意:給出乙個n*m的字元矩陣t,你的任務是找出給定的x *y的字元矩陣p出現了多少次?

藍書上一道題,利用ac自動機解決多模板匹配,同時有一些技巧,把p每一行拆出建立ac自動機,在用t的每一行來匹配,當p的第i行出現在t的第r行,起始列編號為c時,意味著cou

nt[r

−i][

j]

count[r-i][j]

count[

r−i]

[j]應該加1,cou

nt[i

][j]

count[i][j]

count[

i][j

]代表以(i,j)為左上頂點與p相同大小的矩陣與p匹配了多少行。

//please ac

#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;

typedef long long ll;

const int maxn=1000*1000+5;

const int sigma_size=26;

int ch[maxn][sigma_size],val[maxn],sz;

int f[maxn],last[maxn],nxt[1005];//字尾鏈結

int idx(char c)

void init()

void insert(char *s,int v)

}void find(char *t,int r)//在t中找模板

{ int len=strlen(t);

int j=0;

for(int i=0;i​ 把每次列印的串建立ac自動機,順便建立fail樹。查詢第x個字串在第y個字串**現了幾次,其實就是找到fail樹中x的單詞節點的子樹中有多少個點屬於y.維護子樹中內容,想到可以使用dfs序用樹狀陣列或線段樹維護。那麼對於查詢我們也可以用trie樹來維護y,查詢時就dfs trie樹,進入單點更新給對應節點+1,退出單點更新-1,遇到單詞節點查詢對應x節點子樹權值和,賦給對應查詢答案。

​ 做本題時,到想到線段樹維護dfs序都比較順利,用trie維護查詢想了挺久,**敲了半天,但感覺實現起來還是有很多注意的,改的有點自閉,之後重新想一想再把**補上吧。

ac自動機 匹配最長字首 高階 AC自動機詳解

今天我們來介紹一點高階的知識 ac自動機。ac自動機是什麼呢?是不是用了這個演算法,不管什麼題目都會自動ac呢?別做夢啦 ac自動機,是aho corasick automaton的簡稱,該演算法在1975年產生於貝爾實驗室,是著名的多模匹配演算法。ac自動機是對字典樹演算法的一種延伸,是字串中運用...

ac自動機 匹配最長字首 多模匹配 AC自動機

精確的字串匹配演算法有 單模匹配演算法,比如,kmp bm演算法等 和 多模匹配演算法,比如,wu manber ac演算法等。ac演算法 aho corasick 是kmp演算法向多模式串情形的擴充套件,該演算法使用一種特殊的自動機,即ac自動機。ac自動機由一組模式串p生成,是trie的擴充套件...

AC自動機 建立nlogn個AC自動機

string set queries 題意 給你3種操作,1 加入乙個串到集合中。2 刪除集合中的某乙個串 3 查詢集合中的字串在給定的字串種出現幾次。同乙個串可重複 解法 建立多個ac自動機,用二進位制分組來處理。加入給你21個串 分為 16 4 1,再新增乙個串的時候,即21 1,22 16 4...