字串1 KMP,字串最小表示法,AC自動機

2021-09-11 06:26:31 字數 3315 閱讀 1479

kmp演算法:

由於只有乙個模式串,所以我們只需要充分利用這個模式串的資訊即可

我們考慮一下對於乙個匹配串,我們不妨設已經匹配到了模式串的第i個位置,且在匹配串的第j位,如果第i+1個位置不能匹配,那麼我們如果用樸素的匹配思想的話是只能跳到第j-i+2為再一位一位去匹配

但是這樣的我們並沒有利用到該模式串的資訊,也沒有利用已經匹配那些字元的資訊

所以我們就引入了乙個東西叫做nxt陣列,nxt[i]表示當前模式串以第i個位置為結尾的字首串的最長字尾的長度滿足他是該模式串的乙個字首,也就是如果匹配到第i個位置之後不在匹配了,那麼我們就可以直接找到最近的那個起點繼續匹配

nxt陣列只需要遞推就行了

時間複雜度為o(n+m)因為你實際上每次往下匹配就是右移字串結尾位置,每次利用nxt陣列實際上就是右移字串起始位置,所以線性時間複雜度顯然

【模板】kmp字串匹配

#includeusing namespace std;

const int maxn=1e6+10;

int nxt[maxn];

char a[maxn],b[maxn];

int lena,lenb;

void init()

}void solve()

}int main()

字串最小迴圈表示法:

給你乙個字串,讓你求他的最小迴圈表示,也就是把這個字串看做乙個環,讓你求出從某個位置開始的最小字串

我們思考一下這個東西怎麼求

我們設給定的串為s

我們首先考慮兩個指標i,j表示我們考慮起始位置為i,j的字串,如果滿足s[i....i+k-1]=s[j....j+k-1]且s[i+k]!=s[j+k]

這時候我們考慮一下

如果s[i+k]為什麼?

我們考慮一下這個貪心,拿s[i+k]如果此時我們發現以j...j+k為開頭的字串一定不可能作為最小迴圈的起始位置,因為他恰好已經被i....i+k給統統叉掉了

模板:

#includeusing namespace std;

const int maxn=30010;

char a[maxn<<1];

int n;

int main()

int i,j,k;

for (i=1,j=2;i<=n&&j<=n;)

bzoj1398

#includeusing namespace std;

const int n=1e6+10;

char s[n],s1[n];

int la(char *a,int n)

int i,j,k;

for (i=1,j=2;i<=n&&j<=n;)

int main()

if (f[now][s[x]-'a'])

else

}void make()

else }}

void findans()

;node edge[maxn<<1];

int tree[maxn],dfn[maxn],fa[maxn];

vector>q[maxn];

int head[maxn],size[maxn];

int k,dfstime,cnt,po[maxn],n,nxt[maxn],ans[maxn],m,x,y;

char s[maxn];

int f[maxn][26];

void add(int x,int y)

int lowbit(int x)

void adit(int x,int y)

}int find(int x)

return ans;

}int dfs(int now)

return size[now];

}void init()

else

} else

if (s[i]=='b')

else

}void make()

else add(0,f[t][i]);

q.push(f[t][i]);

} else f[t][i]=f[nxt[t]][i]; }}

void solve()

else

if (s[i]=='b')

else

}}void make_ac()

else t=fail[t];

}fail[it->second]=(t?t:1);

e[fail[it->second]].push_back(it->second);

sum[it->second]+=sum[fail[it->second]];

q.push(it->second);} }

}int get_lca(int x,int y)

void lalala(int now,int goal)

else

}void make_tree(int now)

else

}if (sta[top]!=lca) sta[++top]=lca;

}sta[++top]=s[i];

}lalala(sta[top],1); ans[now]+=sum[sta[top]];

}int dfs1(int now,int d)

return size[now];

}void dfs2(int now,int la)

}int main()

scanf("%d",&x);

for (int j=1;j<=x;j++)

}cnt=1;

for (int i=1;i<=m;i++)

s_la[i]=now;

sum[now]++;

}make_ac();

// cout << 1 << endl;

dfs1(1,1);

dfs2(1,1);

for (int i=1;i<=n;i++)

else

if (now) else now=1;}}

len=b[i].size();

now=1;

for (int j=0;jelse

if (now) else now=1;}}

make_tree(i);

}for (int i=1;i<=m;i++) printf("%d\n",findans(1,cnt,1,dfn[s_la[i]]));

for (int i=1;i<=n;i++) printf("%d ",ans[i]);

}

字串最小表示法

最小表示法的定義 給定乙個字串,不斷地把最後乙個元素移到最前面,可得有n個這樣的字串 稱這n個字串是迴圈同構的 那麼最小表示就是這n個裡面字典序最小的乙個 怎麼求最小表示 wrong 最樸素的方法,把每乙個這樣的字串求出來,然後一一比較,找到字典序最小的迴圈同構串 然後資料範圍變大肯定會超時 那麼正...

字串最小表示法

乙個長度為n的首尾相連的字串可以有n種表示法,例如串 abcd 還可以表示bcda,cdab,dabc當我們面臨這樣的字串的時候,我們很難統計相同字串的個數。因此我們引入一種字串的最小表示法來使這些串變得相同。字串的最小表示法是將原來的字串旋轉得到的字典序最小的串 設字串st的長度為len,我們可以...

模板 字串演算法 字串最小表示法

2014年10月,剛進hdu參加新生賽的時候,就遇到了字串最小表示法的裸題,然而那時什麼都不會的我只得寫暴力,自然tle了。之後在 湖南師範大學第六屆大學生計算機程式設計競賽2b 上,又做到了同樣的裸題。字串演算法 字串最小表示法模板 這是乙個可以用o n 時間解決 字串呈環狀,每一位置都可以作為首...