227 高翊恩
#include <bits/stdc++.h>
using namespace std;
int main() {
string s = "abcdefg";
cout << s.size() << endl; // 7
cout << s.find('f') << endl; // 5
cout << s.find('z') << endl; // 4294967295
cout << s.substr(2, 3) << endl; // "cde"
return 0;
}
#include <bits/stdc++.h>
using namespace std;
string Prefix(string s, string i) {
return s.substr(0, i);
}
string Suffix(string s, string i) {
return s.substr(i, s.size() - i);
}
int main() {
string s = "abcdefg";
cout << Prefix(s, 3) << endl; // "abc"
cout << Suffix(s, 4) << endl; // "defg"
cout << Prefix(s, 0) << endl; // ""
return 0;
}
#include <bits/stdc++.h>
using namespace std;
bool isPD(string s) {
int n = s.size();
for (int i = 0; i < (n >> 1); i++) if (s[i] != s[n - i + 1]) return false;
return true;
}
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<string> v;
for (auto &i : v) cin >> i;
sort(v.begin(), v.end());
for (auto &i : v) cout << i << endl;
return 0;
}
\(aa\)
\(aba\)
\(bb\)
\(bba\)
試試看:
\(aa\)
\(aba\)
\(bb\)
\(bba\)
試試看:
struct TrieNode {
int C;
vector<TrieNode*> child;
TrieNode() {
C = 0;
child = vector<TrieNode*>(26, nullptr);
}
void push(string s) {
TrieNode *now = this;
for (auto &i : s) {
if (now -> child[i - 'a'] == nullptr) now -> child[i - 'a'] = new TrieNode();
now = now -> child[i - 'a'];
}
now -> C++;
}
};
其實滿單純的
\(\Omicron(n^2\log n)\)
來把\(\log\)壓掉
來把\(\log\)壓掉
dp[] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
val | 1 | 0 | 1 | 0 |
\(a\)
\(a\)
\(b\)
\(b\)
\(c\)
dp[] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
val | 1 | 0 | 1 | 0 |
\(a\)
\(a\)
\(b\)
\(b\)
\(c\)
dp[] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
val | 1 | 0 | 1 | 0 |
\(a\)
\(a\)
\(b\)
\(b\)
\(c\)
dp[] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
val | 1 | 0 | 1 | 0 |
\(a\)
\(a\)
\(b\)
\(b\)
\(c\)
dp[] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
val | 1 | 0 | 1 | 0 |
\(a\)
\(a\)
\(b\)
\(b\)
\(c\)
dp[] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
val | 1 | 0 | 1 | 0 |
\(a\)
\(a\)
\(b\)
\(b\)
\(c\)
dp[] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
val | 1 | 0 | 1 | 0 |
\(a\)
\(a\)
\(b\)
\(b\)
\(c\)
dp[] | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
val | 1 | 0 | 1 | 0 | 2 |
\(a\)
\(a\)
\(b\)
\(b\)
\(c\)
16進位制
\(\Sigma=\{0\dots9,A\dots F\}\)
轉換方式:
\(\mathbf{8E5C}_{16}={36444}_{10}\)
26進位制
\(\Sigma=\{a\dots z\}\)
轉換方式:
\(\mathbf{pring}_{26}={7159184}_{10}\)
問題1
\(a\rightarrow0\)
\(\mathbf{pring}_{26}=\mathbf{aaaaapring}_{26}\)
27進位制
\(\Sigma=\{a\dots z\}\)
\(\{a,b,\dots,z\}\rightarrow\{1,2,\dots,26\}\)
轉換方式:
\(\mathbf{pring}_{27}={8864296}_{10}\)
問題2
數字太大啦!!
所以送它一個\(\%\)
27進位制
\(\Sigma=\{a\dots z\}\)
\(\{a,b,\dots,z\}\rightarrow\{1,2,\dots,26\}\)
最後要\(\%(1e9+7)\)
轉換方式:
\(\mathbf{pring}_{27}={8864296}_{10}\)
正著做:
\(Hash(s)=(s_0p^0+s_1p^1+s_2p^2+\dots+s_{|s|-1}p^{|s|-1})\%M\)
反著做:
\(hsaH(s)=(s_0p^{|s|-1}+s_1p^{|s|-2}+s_2p^{|s|-3}+\dots+s_{|s|-1}p^0)\%M\)
Hash做字串匹配
\(s=abbabbab\)
\(t=abbab\)
\(Hash(t)=1084078\)
[from, to) | substring of s | Hash() |
---|---|---|
[0, 5) | abbab | 1084078 |
[1, 6) | bbabb | 1103033 |
[2, 7) | babba | 572294 |
[3, 8) | abbab | 1084078 |
可不可以利用\(Hash(s.substr(0, i))\),只用\(\Omicron(1)\)求出\(Hash(s.substr(1, i))\)?
\(s_0s_1s_2s_3s_4\longrightarrow h\)
\(s_1s_2s_3s_4\longrightarrow h-s_0p^{|t|}\)
\(s_1s_2s_3s_4\_\longrightarrow (h-s_0p^{|t|})\times 27\)
\(s_1s_2s_3s_4s_5\longrightarrow (h-s_0p^{|t|})\times 27+s_5\)
記得有模運算
這裡用的是\(hsaH\)
開一個陣列\(Pref\)記錄\(Hash(P_s[i])\)
則可以用\(\Omicron(1)\)求出\((\sum\limits_{i=l}^{r-1}s_ip^i)\%M\)
可是我們要的是\((\sum\limits_{i=l}^{r-1}s_ip^{i-l})\%M\)
int mod;
int PLUS(int x, int y) {
return (x + y) % mod;
}
int MINUS(int x, int y) {
return (x - (y % mod) + mod) % mod;
}
int TIMES(int x, int y) {
return (x * y) % mod;
}
\(\ \ \ \ \ Q\times Q^{-1}=1\)
\(\Rightarrow Q\times Q^{-1}\equiv1(\mod M)\)
所以想辦法找到\(Q^{-1}\)就好了
費馬小定理
\(a^p\equiv a(\mod p)\)
\(a<p\Rightarrow a^{p-1}\equiv1(\mod p)\)
\(\Rightarrow a^{p-2}\equiv a^{-1}(\mod p)\)
int modPow(int a, int x) {
int ans = 1;
for (int i = 1 << 30; i > 0; i >>= 1) {
ans = ans * ans % mod;
if (i & x) ans = ans * a % mod;
}
return ans;
}
int DIVIDE(int x, int y) {
return x * modPow(y, mod - 2) % mod;
}
int mod;
int modPow(int a, int x) {
int ans = 1;
for (int i = 1 << 30; i > 0; i >>= 1) {
ans = ans * ans % mod;
if (i & x) ans = ans * a % mod;
}
return ans;
}
struct Hash {
int p;
vector<int> pref;
Hash(string s, int _p) {
p = _p;
int n = s.size();
pref.resize(n + 1);
int mul = 1;
pref[0] = 0;
for (int i = 0; i < n; i++) {
pref[i + 1] = (pref[i] + (s[i] - 'a' + 1) * mul) % mod;
mul = mul * p % mod;
}
}
int query(int from, int len) {
int ans = (pref[from + len] - pref[from] + mod) % mod;
return ans * modpow(modpow(p, mod - 2), from) % mod;
}
};
我喜歡叫它CPS (Common Prefix and Suffix)
字串 | CPS(0) | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|---|
"abcabca" | "abcabca" | "abca" | "a" | "" |
"abcde" | "abcde" | "" | --- | --- |
"zzz" | "zzz" | "zz" | "z" | "" |
字串 | CPS(0) | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|---|
"abcabca" | 7 | 4 | 1 | 0 |
"abcde" | 5 | 0 | -1 | -1 |
"zzz" | 3 | 2 | 1 | 0 |
\(s=abbabbab\)
s的前綴 | CPS(0) | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|---|
"" | "" | --- | --- | --- |
"a" | "a" | "" | --- | --- |
"ab" | "ab" | "" | --- | --- |
"abb" | "abb" | "" | --- | --- |
"abba" | "abba" | "a" | "" | --- |
"abbab" | "abbab" | "ab" | "" | --- |
"abbabb" | "abbabb" | "abb" | "" | --- |
"abbabba" | "abbabba" | "abba" | "a" | "" |
"abbabbab" | "abbabbab" | "abbab" | "ab" | "" |
\(s=abbabbab\)
Ps[i] | CPS(0) | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|---|
0 | 0 | -1 | -1 | -1 |
1 | 1 | 0 | -1 | -1 |
2 | 2 | 0 | -1 | -1 |
3 | 3 | 0 | -1 | -1 |
4 | 4 | 1 | 0 | -1 |
5 | 5 | 2 | 0 | -1 |
6 | 6 | 3 | 0 | -1 |
7 | 7 | 4 | 1 | 0 |
8 | 8 | 5 | 2 | 0 |
Ps[i] | CPS(0) | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|---|
0 | 0 | -1 | -1 | -1 |
1 | 1 | 0 | -1 | -1 |
2 | 2 | 0 | -1 | -1 |
3 | 3 | 0 | -1 | -1 |
4 | 4 | 1 | 0 | -1 |
5 | 5 | 2 | 0 | -1 |
6 | 6 | 3 | 0 | -1 |
7 | 7 | 4 | 1 | 0 |
8 | 8 | 5 | 2 | 0 |
↑ 這一行沒用
Ps[i] | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|
0 | -1 | -1 | -1 |
1 | 0 | -1 | -1 |
2 | 0 | -1 | -1 |
3 | 0 | -1 | -1 |
4 | 1 | 0 | -1 |
5 | 2 | 0 | -1 |
6 | 3 | 0 | -1 |
7 | 4 | 1 | 0 |
8 | 5 | 2 | 0 |
觀察性質
Ps[i] | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|
0 | -1 | -1 | -1 |
1 | 0 | -1 | -1 |
2 | 0 | -1 | -1 |
3 | 0 | -1 | -1 |
4 | 1 | 0 | -1 |
5 | 2 | 0 | -1 |
6 | 3 | 0 | -1 |
7 | 4 | 1 | 0 |
8 | 5 | 2 | 0 |
觀察性質
Ps[i] | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|
0 | -1 | -1 | -1 |
1 | 0 | -1 | -1 |
2 | 0 | -1 | -1 |
3 | 0 | -1 | -1 |
4 | 1 | 0 | -1 |
5 | 2 | 0 | -1 |
6 | 3 | 0 | -1 |
7 | 4 | 1 | 0 |
8 | 5 | 2 | 0 |
觀察性質
Ps[i] | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|
0 | -1 | -1 | -1 |
1 | 0 | -1 | -1 |
2 | 0 | -1 | -1 |
3 | 0 | -1 | -1 |
4 | 1 | 0 | -1 |
5 | 2 | 0 | -1 |
6 | 3 | 0 | -1 |
7 | 4 | 1 | 0 |
8 | 5 | 2 | 0 |
觀察性質
\(s.CPS(2)=s.CPS(1).CPS(1)\)
\(abbabba\) → \(abba\) → \(a\)
\(abba\) → \(a\)
\(abbabba\)
\(abbabba\)
\(abbabba\)
\(abba\)
\(abbabba\)
\(abba\)
\(abbabba\)
\(abba\)
\(abbabba\)
\(abba\)
\(a\)
\(abbabba\)
\(abba\)
\(a\)
我們可以推得:
若\(t\in s.CPS\)
則\(t.CPS\subset s.CPS\)
根據定義:\(s.CPS(1)\)為「除了\(s\)本身的最長\(CPS\)」
再認真想一下,我們可以發現
\(s.CPS(a+b)=s.CPS(a).CPS(b)\)
Ps[i] | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|
0 | -1 | -1 | -1 |
1 | 0 | -1 | -1 |
2 | 0 | -1 | -1 |
3 | 0 | -1 | -1 |
4 | 1 | 0 | -1 |
5 | 2 | 0 | -1 |
6 | 3 | 0 | -1 |
7 | 4 | 1 | 0 |
8 | 5 | 2 | 0 |
Ps[i] | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|
0 | -1 | -1 | -1 |
1 | 0 | -1 | -1 |
2 | 0 | -1 | -1 |
3 | 0 | -1 | -1 |
4 | 1 | 0 | -1 |
5 | 2 | 0 | -1 |
6 | 3 | 0 | -1 |
7 | 4 | 1 | 0 |
8 | 5 | 2 | 0 |
Ps[i] | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|
0 | -1 | -1 | -1 |
1 | 0 | -1 | -1 |
2 | 0 | -1 | -1 |
3 | 0 | -1 | -1 |
4 | 1 | 0 | -1 |
5 | 2 | 0 | -1 |
6 | 3 | 0 | -1 |
7 | 4 | 1 | 0 |
8 | 5 | 2 | 0 |
Ps[i] | CPS(1) | CPS(2) | CPS(3) |
---|---|---|---|
0 | -1 | -1 | -1 |
1 | 0 | -1 | -1 |
2 | 0 | -1 | -1 |
3 | 0 | -1 | -1 |
4 | 1 | 0 | -1 |
5 | 2 | 0 | -1 |
6 | 3 | 0 | -1 |
7 | 4 | 1 | 0 |
8 | 5 | 2 | 0 |
令\(t\)為\(P_s\)的其中一個元素
則有\(t.CPS\subseteq P_s\)
如果我們對所有\(s\)的前綴,記錄其\(CPS(1)\)
則\(t.CPS(2)=t.CPS(1).CPS(1)\)
很容易就可以得到\(t.CPS(2)\)
又\(t.CPS(3)=t.CPS(2).CPS(1)\)
很容易就可以得到\(t.CPS(3)\)
...
Ps[i] | CPS(1) |
---|---|
0 | -1 |
1 | 0 |
2 | 0 |
3 | 0 |
4 | 1 |
5 | 2 |
6 | 3 |
7 | 4 |
8 | 5 |
當我們要找\(s\)的第7個前綴的所有共同前後綴時
\(P_s[7].CPS(1)\)
\(P_s[7].CPS(2)\)
\(P_s[7].CPS(3)\)
\(s=abbabbab\)
\(\pi_s=\{-1,0,0,0,1,2,3,4,5\}\)
vector<int> Pi(string s) {
int n = s.size();
vector<int> result(n + 1);
result[0] = -1;
for (int i = 1; i < n; i++) {
for (int j = i - 1; j >= 0; j--) {
if (s.substr(0, j) == s.substr(i - j + 1, j)) {
result[i] = j;
break;
}
}
}
return result;
}
複雜度:\(O(n^3)\)
超級慢
初始條件:
\(\pi[0]=-1,\pi[1]=0\)
\(P_s[\pi_s[i+1]-1]\in P_s[i].CPS\)
\(\underbrace{\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$}\dots\)
\(P_s[i+1]\)
假設我們要找\(\pi_s[i+1]\)
找\(\pi_s[i+1]\)時
令\(j=1,2,\dots\)
如果\(P_s[i].CPS(j)\)的「下一個字元」\(==s[i+1]\)
則\(\pi_s[i+1]=P_s[i].CPS(j)+1\)
\(\underbrace{\$\$\$\$\$\$\$?\$\$\$\$\$\$\$\$\$\$?}\dots\)
\(P_s[i+1]\)
\(s=abbacabbab\dots\)
\(\pi_s=\{-1, 0, 0, 0, 1, 0, 1, 2, 3, 4, ?\}\)
\(abbacabba\ b\)
\(s=abbacabbab\dots\)
\(\pi_s=\{-1, 0, 0, 0, 1, 0, 1, 2, 3, 4, ?\}\)
\(abbacabba\ b\)
\(P_s[9].CPS(1)=\pi_s[9]=4\)
\(s=abbacabbab\dots\)
\(\pi_s=\{-1, 0, 0, 0, 1, 0, 1, 2, 3, 4, ?\}\)
\(abbacabba\ b\)
\(P_s[9].CPS(1)=\pi_s[9]=4\)
\(s=abbacabbab\dots\)
\(\pi_s=\{-1, 0, 0, 0, 1, 0, 1, 2, 3, 4, ?\}\)
\(abbacabba\ b\)
\(P_s[9].CPS(2)=\pi_s[\pi_s[9]]=1\)
\(s=abbacabbab\dots\)
\(\pi_s=\{-1, 0, 0, 0, 1, 0, 1, 2, 3, 4, ?\}\)
\(abbacabba\ b\)
\(P_s[9].CPS(2)=\pi_s[\pi_s[9]]=1\)
\(s=abbacabbab\dots\)
\(\pi_s=\{-1, 0, 0, 0, 1, 0, 1, 2, 3, 4, ?\}\)
\(abbacabba\ b\)
\(\pi_s[9+1]=1+1=2\)
現場打!
\(abbaabbab\)
\(abbaabbab\)
\(abbab\)
\(abbab\)
\(abbab\)
\(abbab\)
\(abbab\)
拿\(t\)往右推
\(t\)每次往右推一格
\(abbaabbab\)
\(abbab\)
\(abbab\)
\(abbab\)
\(abbab\)
\(abbab\)
拿\(t\)往右推
可不可以預知這兩個「壯志未酬身先死」?
\(t\)每次往右推一格
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
\(t[j]\)
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
\(t[j-x]\)
證明當\(s[i]\neq t[j]\)時候:
那我們這個操作就可以將\(t\)向右推\(S\)中最小的
\(\dots\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\dots\)
\(t\)往右推了\(x\)格
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
\(t[j]\)
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
\(t[j-x]\)
證明當\(s[i]\neq t[j]\)時候:
那我們這個操作就可以將\(t\)向右推\(S\)中最小的
\(\dots\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\dots\)
\(t\)往右推了\(x\)格
好啦其實就是\(CPS\)啦
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
\(t[j]\)
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
\(t[j-x]\)
證明當\(s[i]\neq t[j]\)時候:
那我們這個操作就可以將\(t\)向右推\(S\)中最小的
\(\dots\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\dots\)
\(t\)往右推了\(x\)格
好啦其實就是\(CPS\)啦
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
\(t[j]\)
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
\(t[j-x]\)
假設\(j-x\notin P_t[j].CPS\)
且成功配到藍色格子
\(\dots\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\dots\)
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
\(t[j]\)
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
假設\(j-x\notin P_t[j].CPS\)
且成功配到藍色格子
\(\dots\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\dots\)
\(t[j-x]\)
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
\(t[j]\)
\(\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\)
假設\(j-x\notin P_t[j].CPS\)
且成功配到藍色格子
\(\dots\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\ \$\dots\)
則\(j-x\in P_t[j].CPS\)
\(\Rightarrow\)只有推\(x\)格的人可以活下來
\(t[j-x]\)
所以發現錯誤的時候
就找現在配到的字串的\(CPS(1)\ (\pi)\)
然後從剛剛錯的地方繼續
\(abbaabbab\)
\(abbab\)
\(abbab\)
\(abbab\)
\(abbabbab\)
\(abbab\)\(\$\)
\(abbab\)
vector<int> StringMatching(string s, string t) {
int n = s.size(), m = t.size();
vector<int> pi = Pi(t), ans;
s.push_back('^');
t.push_back('$');
for (int i = 0, j = 0; i < n + 1; i++, j++) {
if (j == m) ans.push_back(i - m);
while (j >= 0 && s[i] != t[j]) j = pi[j];
}
return ans;
}
另一種想法
只要把\(t,\$,s\)連起來
然後做\(\pi\)
然後數\(\$\)後面哪些的\(\pi\)值是\(|t|\)
vector<int> stringMatching(string s, string t) {
int m = t.size();
vector<int> v;
vector<int> pi = Pi(t + "$" + s);
for (int i = 0; i < pi.size(); i++) {
if (pi[i] == m) v.push_back(i - m - m);
}
return v;
}
為什麼不先講這個\(\dots\)
前綴自動機
\(\dots abbaa\dots\)
\(abbab\)
\(abbab\)
\(abbab\)
優化再優化!
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(t=abbab\)
對\(t\)開一張\(PA\)表:
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
\(abbaabbab\)
i | 'a' | 'b' |
---|---|---|
0 | 1 | 0 |
1 | 1 | 2 |
2 | 1 | 3 |
3 | 4 | 0 |
4 | 1 | 5 |
5 | 1 | 3 |
\(abbab\)
vector<vector<int>> PrefixAutomaton(string s) {
int n = s.size();
vector<vector<int>> dp(n + 1, vector<int>(26, 0));
vector<int> pi = Pi(s);
s += '$';
dp[0][s[0] - 'a'] = 1;
for (int i = 1; i <= n; i++) for (int j = i; j >= 0; j = pi[j]) if (j < n) dp[i][s[j] - 'a'] = max(dp[i][s[j] - 'a'], j + 1);
return dp;
}
vector<int> StringMatching(string s, string t) {
int n = s.size(), m = t.size();
auto PA = PrefixAutomaton(t);
vector<int> ans;
for (int i = 0, j = 0; i < n; i++) {
j = PA[j][s[i] - 'a'];
if (j == m) ans.push_back(i - m + 1);
}
return ans;
}
建表:\(\Omicron(n)\)
配對:\(\Omicron(1)/\)每個字元
給定三字串\(s_0,s_1,t\)和一整數\(n\)
令\(s_{i+1}=5\times s_i+6\times s_{i-1},i\in\mathbb{Z}^+\)
求在\(s_n\)裡面可以找到幾個\(t\)
給定三字串\(s_0,s_1,t\)和一整數\(n\)
令\(s_{i+1}=5\times s_i+6\times s_{i-1},i\in\mathbb{Z}^+\)
求在\(s_n\)裡面可以找到幾個\(t\)
顯然地
\(|s_n|=\frac{1}{7}\{[6\times(-1)^n+6^n]|s_0|+[6^n-(-1)^n]|s_1|\}\)
直接用\(\pi\)會炸
直接用\(PA\)也會炸
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | 2 |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | 2 |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | 2 |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | 2 |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | (+1) |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | 2 |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | (+1) |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | 2 |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | (+1) |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | 2 |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | (+1) |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | 2 |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | (+1) |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | 2 |
1 | 1 | 2 | |
2 | 1 | 3 | |
3 | 4 | 0 | |
4 | 1 | 5 | 2 (+1) |
5 | 1 | 3 |
\(t=abbab\)
i | 'a' | 'b' | "bab" |
---|---|---|---|
0 | 1 | 0 | 2 |
1 | 1 | 2 | 2 |
2 | 1 | 3 | 5 (+1) |
3 | 4 | 0 | 2 |
4 | 1 | 5 | 2 (+1) |
5 | 1 | 3 | 5 (+1) |
\(t=abbab\)
\(一台自動機=\langle Q,\Sigma,\delta,q_0,F\rangle\)
\(=\langle狀態,字母表,轉移函式,初始狀態,終止狀態\rangle\)
\(Q=圈圈們\)
\(\Sigma=\{a,b\}\)
\(\delta=箭頭們\)
\(q_0=橘色圈圈\)
\(F=綠色圈圈們\)
走走看:\(abbaabbab\)
\(t=abbab\)
走走看:\(abbaabbab\)
\(\delta(q,c)=\)
\(在q所代表的字串+c中,\)
有出現在樹上的最長後綴
\(\delta(q,c)=\)
\(在q所代表的字串+c中,\)
有出現在樹上的最長後綴
\(\delta(q,c)=\)
\(在q所代表的字串+c中,\)
有出現在樹上的最長後綴
\(\delta(q,c)=\)
\(在q所代表的字串+c中,\)
有出現在樹上的最長後綴
走走看:\(abbaabbab\)
初始條件:
\(q[0].SIT(1)=nullptr\)
\(q[i].SIT(1)=q[0]\)
\(\forall q[i]\in depth(1)\)
\(\$\$\$\$\$\$\$\$\$\ \$\)
藍色\(\in Trie\)
假設紅色為\(q_i.SIT(1)\)
則紅色\(\in Trie\)
則綠色\(\in Trie\)
則綠色\(\in\)藍色的\(SIT\)
\(q_i\)
\(q_i\)
找\(q[i].SIT(1)\)時
令\(j=1,2,\dots\)
如果\(q[i].father.SIT(j)\)有辦法走\(q[i].lastChar\)
則\(q[i].SIT(1)=q[i].father.SIT(j).next[q[i].lastChar]\)
\(\$\$\$\$\$\$\$\$\$\ \$\)
如果他有辦法往\(a\)走的話
那個\(a\)就會是\(SIT\)
但它顯然沒有
好耶
做它的\(SL\)
好耶
走走看:\(abbaabbab\)
在\(abbabbab\)中匹配下列字串:
\(abbab\)
\(bab\)
\(ba\)
在\(abbabbab\)中匹配下列字串:
\(abbab\)
\(bab\)
\(ba\)
在\(abbabbab\)中匹配下列字串:
\(abbab\)
\(bab\)
\(ba\)
在\(abbabbab\)中匹配下列字串:
\(abbab\)
\(bab\)
\(ba\)
為什麼配不到\(bab\)和\(ba\)?
struct TrieNode {
int id;
char lastChar;
TrieNode *next[26];
TrieNode *SL;
TrieNode *AL;
TrieNode(TrieNode *parent = nullptr, char _lastChar = '\0') {
id = -1;
lastChar = _lastChar;
fill(next, next + 26, nullptr);
SL = parent;
AL = nullptr;
}
void push(string s, int _id) {
TrieNode *now = this;
for (auto &i : s) {
if (now -> next[i - 'a'] == nullptr) now -> next[i - 'a'] = new TrieNode(now, i);
now = now -> next[i - 'a'];
}
now -> id = _id;
}
void construct() {
queue<TrieNode*> q;
for (auto &i : next) {
if (i == nullptr) continue;
q.push(i);
}
while (q.size()) {
TrieNode *now = q.front();
q.pop();
for (auto &i : now -> next) {
if (i == nullptr) continue;
q.push(i);
}
TrieNode *back = now -> SL -> SL;
while (back && back -> next[now -> lastChar - 'a'] == nullptr) back = back -> SL;
if (back) now -> SL = back -> next[now -> lastChar - 'a'];
else now -> SL = this;
if (now -> SL -> id != -1) now -> AL = now -> SL;
else now -> AL = now -> SL -> AL;
}
}
};
struct AC {
vector<string> s;
TrieNode *root;
AC(vector<string> _s) {
s = _s;
root = new TrieNode();
}
void push(string _s) {
s.push_back(_s);
}
void construct() {
int n = s.size();
for (int i = 0; i < n; i++) root -> push(s[i], i);
root -> construct();
}
vector<int> stringMatching(string _s) {
int n = s.size();
vector<int> ans(n);
TrieNode *now = root;
for (auto &i : _s) {
while (now && now -> next[i - 'a'] == nullptr) now = now -> SL;
if (now) now = now -> next[i - 'a'];
else now = root;
if (now -> id != -1) ans[now -> id]++;
TrieNode *back = now -> AL;
while (back) {
ans[back -> id]++;
back = back -> AL;
}
}
return ans;
}
};
\(s=abbabbab\)
\(z_s=\{\_,0,0,5,0,0,2,0\}\)
對\(t+"\$"+s\)做\(z\)
就好了
zzz
\(\$\$\$\$\$\$A\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
令\(l=\argmax\limits_j(j+z_s[j])\)
現在已經配到最右邊的那個人
我們現在要找\(z_s[i]\)
根據\(i\)的位置,可以分成\(2\)種情況:
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(\$\$\$\$\$\$A\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
這個時候我們令\(i'=i-l\)
即Prefix中對應到的\(i\)
\(i\)
\(\$\$\$\$\$\$A\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
這個時候我們令\(i'=i-l\)
即Prefix中對應到的\(i\)
\(i\)
\(i'\)
\(\$\$C\$\$DA\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
1-1. \(i'+z_s[i']<z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(i'\)
\(\$\$C\$\$DA\$\$\$\$\$C\$\$DB\$\$\$\dots\)
1-1. \(i'+z_s[i']<z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(i'\)
\(\$\$C\$\$DA\$\$\$\$\$C\$\$DB\$\$\$\dots\)
1-1. \(i'+z_s[i']<z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(i'\)
\(\Rightarrow z_s[i]=z_s[i']\)
\(\$\$\$C\$\$A\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
1-2. \(i'+z_s[i']=z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(i'\)
\(\$\$\$C\$\$A\$\$\$\$\$\$C\$\$B\$\$\$\dots\)
1-2. \(i'+z_s[i']=z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(i'\)
\(\$\$\$C\$\$A\$\$\$\$\$\$C\$\$B\$\$\$\dots\)
1-2. \(i'+z_s[i']=z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(i'\)
\(A\neq B\)
\(C\neq B\)
\(A\neq C?\)
\(\$\$\$C\$\$A\$\$\$\$\$\$C\$\$B\$\$\$\dots\)
1-2. \(i'+z_s[i']=z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(i'\)
所以這個時候
只能確定\(z_s[i]\geq z_s[i']\)
那就繼續配下去
\(\$\$\$\$C\$AD\$\$\$\$\$\$\$\$B\$\$\$\dots\)
1-3. \(i'+z_s[i']>z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(i'\)
\(\$\$\$\$C\$AD\$\$\$\$\$\$C\$B\$\$\$\dots\)
1-3. \(i'+z_s[i']>z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(i'\)
\(\$\$\$\$C\$AD\$\$\$\$\$\$C\$B\$\$\$\dots\)
1-3. \(i'+z_s[i']>z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(i'\)
\(A\neq B\)
\(\$\$\$\$C\$AD\$\$\$\$\$\$C\$B\$\$\$\dots\)
1-3. \(i'+z_s[i']>z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(i'\)
\(\Rightarrow z_s[i]=z_s[l]-i'\)
\(\$\$\$\$\$\$A\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
2. \(i\geq l+z_s[l]\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
\(\$\$\$\$\$\$A\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
\(l\)
\(z_s[l]\)
\(l+z_s[l]\)
\(i\)
沒料
只好從頭配了
2. \(i\geq l+z_s[l]\)
vector<int> Z(string s) {
int n = s.size();
vector<int> z(n);
z[0] = 0;
int l = 0;
for (int i = 1; i < n; i++) {
if (i >= l + z[l]) { // 2.
for (z[i] = 0; i + z[i] < n && s[z[i]] == s[i + z[i]]; z[i]++);
l = i;
continue;
}
int i_ = i - l;
if (i_ + z[i_] < z[l]) z[i] = z[i_]; // 1-1.
else if (i_ + z[i_] > z[l]) z[i] = z[l] - i_; // 1-3.
else { // 1-2.
for (z[i] = i_; i + z[i] < n && s[z[i]] == s[i + z[i]]; z[i]++);
if (z[i] > z[l]) l = i;
}
}
return z;
}
int stringMatching(string s, string t) {
int n = s.size(), m = t.size(), C = 0;
vector<int> z = Z(t + "$" + s);
for (int i = m + 1; i < n + m + 1; i++) {
if (z[i] == t.size()) C++;
}
return C;
}
終於要用到PD了!
\(abbab\)
\(*a*b*b*a*b*\)
\(s=*a*b*b*a*b*\)
\(z_s=\{0,1,0,1,4,1,0,3,0,1,0\}\)
\(\sum m_s[i]\)
就好了
zzz
\(\$\$A\$\$\$\$\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
我們現在要找\(m_s[i]\)
令\(l=\argmax\limits_{j<i}(j+m_s[j])\)
展開雙翼(?)後最右邊的人
根據\(i\)的位置,可以分成\(2\)種情況:
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(\$\$A\$\$\$\$\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
1. \(i\leq l+m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
這個時候我們令\(i'=l-(i-l)\)
即以\(s[l]\)對稱過去的\(i\)
\(\$\$A\$\$\$\$\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
1. \(i\leq l+m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
這個時候我們令\(i'=l-(i-l)\)
即以\(s[l]\)對稱過去的\(i\)
\(i'\)
\(\$\$AC\$\$\$\$\$D\$\$\$\$\$\$B\$\$\$\dots\)
1-1. \(i'-m_s[i']>l-m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(i'\)
\(\$\$AC\$\$\$\$\$D\$\$\$\$\$CB\$\$\$\dots\)
1-1. \(i'-m_s[i']>l-m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(i'\)
\(\$\$AC\$\$\$\$\$D\$\$\$\$\$CB\$\$\$\dots\)
1-1. \(i'-m_s[i']>l-m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(i'\)
\(\Rightarrow m_s[i]=m_s[i']\)
\(\$\$A\$\$\$\$\$\$\$C\$\$\$\$\$B\$\$\$\dots\)
1-2. \(i'-m_s[i']=l-m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(i'\)
\(\$\$A\$\$\$\$\$C\$C\$\$\$\$\$B\$\$\$\dots\)
1-2. \(i'-m_s[i']=l-m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(i'\)
\(\$\$A\$\$\$\$\$C\$C\$\$\$\$\$B\$\$\$\dots\)
1-2. \(i'-m_s[i']=l-m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(i'\)
\(A\neq B\)
\(C\neq B\)
\(A\neq C?\)
\(\$\$A\$\$\$\$\$C\$C\$\$\$\$\$B\$\$\$\dots\)
1-2. \(i'-m_s[i']=l-m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(i'\)
所以這個時候
只能確定\(m_s[i]\geq m_s[i']\)
那就繼續配下去
\(\$CA\$\$\$\$\$\$\$\$D\$\$\$\$B\$\$\$\dots\)
1-3. \(i'-m_s[i']<l-m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(i'\)
\(\$CA\$\$\$\$D\$\$\$D\$\$\$\$B\$\$\dots\)
1-3. \(i'-m_s[i']<l-m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(i'\)
\(\$CA\$\$\$\$D\$\$\$D\$\$\$\$B\$\$\dots\)
1-3. \(i'-m_s[i']<l-m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(i'\)
\(A\neq B\)
\(\$CA\$\$\$\$D\$\$\$D\$\$\$\$B\$\$\dots\)
1-3. \(i'-m_s[i']<l-m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(i'\)
\(\Rightarrow m_s[i]=i'-l+m_s[l]\)
\(\$\$A\$\$\$\$\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
2. \(i>l+m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
\(\$\$A\$\$\$\$\$\$\$\$\$\$\$\$\$B\$\$\$\dots\)
2. \(i>l+m_s[l]\)
\(l\)
\(l-m_s[l]\)
\(l+m_s[l]\)
\(i\)
沒料
只好從頭配了
vector<int> M(string s) {
string br = "*";
for (auto &i : s) br += string(1, s[i]) + "*";
s = br;
int n = s.size();
vector<int> m(n);
m[0] = 0;
int l = 0;
for (int i = 1; i < n; i++) {
if (i > l + m[l]) {
for (m[i] = 0; i - m[i] - 1 >= 0 && i + m[i] + 1 < n && s[i - m[i] - 1] == s[i + m[i] + 1]; m[i]++);
l = i;
continue;
}
int i_ = l - i + l;
if (i_ - m[i_] > l - m[l]) m[i] = m[i_];
else if (i_ - m[i_] < l - m[l]) m[i] = i_ - l + m[l];
else {
for (m[i] = m[i_]; i - m[i] - 1 >= 0 && i + m[i] + 1 < n && s[i - m[i] - 1] == s[i + m[i] + 1]; m[i]++);
if (i + m[i] > l + m[l]) l = i;
}
}
return m;
}
\(s=abbab\)
\(S_s[0]=\backslash0\)
\(S_s[1]=b\)
\(S_s[2]=ab\)
\(S_s[3]=bab\)
\(S_s[4]=bbab\)
\(S_s[5]=abbab\)
\(S_s[1]=b\)
\(S_s[2]=ab\)
\(S_s[3]=bab\)
\(S_s[4]=bbab\)
\(S_s[5]=abbab\)
\(S_s[0]=\backslash0\)
\(s=abbab\)
\(S_s[0]=\backslash0\)
\(S_s[1]=b\)
\(S_s[2]=ab\)
\(S_s[3]=bab\)
\(S_s[4]=bbab\)
\(S_s[5]=abbab\)
\(S_s[1]=b\)
\(S_s[2]=ab\)
\(S_s[3]=bab\)
\(S_s[4]=bbab\)
\(S_s[5]=abbab\)
\(S_s[0]=\backslash0\)
sort
\(s=abbab\)
\(S_s[0]=\backslash0\)
\(S_s[1]=b\)
\(S_s[2]=ab\)
\(S_s[3]=bab\)
\(S_s[4]=bbab\)
\(S_s[5]=abbab\)
sort
\(サ=\{0,2,5,1,3,4\}\)
vector<int> SA(string s) {
int n = s.size();
vector<int> sa(n + 1);
vector<pair<string, int>> v(n + 1);
for (int i = 0; i <= n; i++) v[i] = {s.substr(i, n - i), i};
sort(v.begin(), v.end());
for (int i = 0; i <= n; i++) sa[i] = v[i].second;
return sa;
}
\(\Omicron(n^2\log n)\)
\(s.cycle(0)=abbab\backslash0\)
\(s.cycle(3)=ab\backslash0abb\)
\(s.cycle(4)=b\backslash0abba\)
\(s.cycle(5)=\backslash0abbab\)
\(s.cycle(1)=bbab\backslash0a\)
\(s.cycle(2)=bab\backslash0ab\)
\(s.cycle(0)=abbab\backslash0\)
\(s.cycle(3)=ab\backslash0abb\)
\(s.cycle(4)=b\backslash0abba\)
\(s.cycle(5)=\backslash0abbab\)
\(s.cycle(1)=bbab\backslash0a\)
\(s.cycle(2)=bab\backslash0ab\)
\(s.cycle(0)=abbab\backslash0\)
\(s.cycle(3)=ab\backslash0abb\)
\(s.cycle(4)=b\backslash0abba\)
\(s.cycle(5)=\backslash0abbab\)
\(s.cycle(1)=bbab\backslash0a\)
\(s.cycle(2)=bab\backslash0ab\)
\(s.cycle(0)=abbab\backslash0\)
\(s.cycle(3)=ab\backslash0abb\)
\(s.cycle(4)=b\backslash0abba\)
\(s.cycle(5)=\backslash0abbab\)
\(s.cycle(1)=bbab\backslash0a\)
\(s.cycle(2)=bab\backslash0ab\)
sort
\(s.cycle(0)=abbab\backslash0\)
\(s.cycle(3)=ab\backslash0abb\)
\(s.cycle(4)=b\backslash0abba\)
\(s.cycle(5)=\backslash0abbab\)
\(s.cycle(1)=bbab\backslash0a\)
\(s.cycle(2)=bab\backslash0ab\)
sort
\(サ=\{5,3,0,4,2,1\}\)
我們其實比較喜歡這個排序
Cyc | string | rank |
---|---|---|
0 | abbab\0 | |
1 | bbab\0a | |
2 | bab\0ab | |
3 | ab\0abb | |
4 | b\0abba | |
5 | \0abbab |
Cyc | string | rank |
---|---|---|
0 | abbab\0 | |
1 | bbab\0a | |
2 | bab\0ab | |
3 | ab\0abb | |
4 | b\0abba | |
5 | \0abbab |
\(_0a\)
Text
\(_1b\)
Text
\(_2b\)
Text
\(_3a\)
Text
\(_4b\)
Text
\(_5\backslash0\)
Text
Cyc | string | rank |
---|---|---|
0 | abbab\0 | |
1 | bbab\0a | |
2 | bab\0ab | |
3 | ab\0abb | |
4 | b\0abba | |
5 | \0abbab |
\(_0a\)
Text
\(_1b\)
Text
\(_2b\)
Text
\(_3a\)
Text
\(_4b\)
Text
\(_5\backslash0\)
Text
Cyc | string | rank |
---|---|---|
0 | abbab\0 | |
1 | bbab\0a | |
2 | bab\0ab | |
3 | ab\0abb | |
4 | b\0abba | |
5 | \0abbab |
\(_0a\)
1
\(_1b\)
3
\(_2b\)
3
\(_3a\)
1
\(_4b\)
3
\(_5\backslash0\)
0
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 1 |
1 | bbab\0a | 3 |
2 | bab\0ab | 3 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0a\)
1
\(_1b\)
3
\(_2b\)
3
\(_3a\)
1
\(_4b\)
3
\(_5\backslash0\)
0
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 1 |
1 | bbab\0a | 3 |
2 | bab\0ab | 3 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0a\ b\)
1
\(_1b\ b\)
3
\(_2b\ a\)
3
\(_3a\ b\)
1
\(_4b\ \backslash0\)
3
\(_5\backslash0\ a\)
0
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 1 |
1 | bbab\0a | 3 |
2 | bab\0ab | 3 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0a\ b\)
1, 3
\(_1b\ b\)
3, 3
\(_2b\ a\)
3, 1
\(_3a\ b\)
1, 3
\(_4b\ \backslash0\)
3, 0
\(_5\backslash0\ a\)
0, 1
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 1 |
1 | bbab\0a | 3 |
2 | bab\0ab | 3 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0a\ b\)
1, 3
\(_1b\ b\)
3, 3
\(_2b\ a\)
3, 1
\(_3a\ b\)
1, 3
\(_4b\ \backslash0\)
3, 0
\(_5\backslash0\ a\)
0, 1
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 1 |
1 | bbab\0a | 3 |
2 | bab\0ab | 3 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0ab\)
1
\(_1bb\)
5
\(_2ba\)
4
\(_3ab\)
1
\(_4b\backslash0\)
3
\(_5\backslash0a\)
0
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 1 |
1 | bbab\0a | 5 |
2 | bab\0ab | 4 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0ab\)
1
\(_1bb\)
5
\(_2ba\)
4
\(_3ab\)
1
\(_4b\backslash0\)
3
\(_5\backslash0a\)
0
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 1 |
1 | bbab\0a | 5 |
2 | bab\0ab | 4 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0ab\ ba\)
1
\(_1bb\ ab\)
5
\(_2ba\ b\backslash0\)
4
\(_3ab\ \backslash0a\)
1
\(_4b\backslash0\ ab\)
3
\(_5\backslash0a\ bb\)
0
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 1 |
1 | bbab\0a | 5 |
2 | bab\0ab | 4 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0ab\ ba\)
1, 4
\(_1bb\ ab\)
5, 1
\(_2ba\ b\backslash0\)
4, 3
\(_3ab\ \backslash0a\)
1, 0
\(_4b\backslash0\ ab\)
3, 1
\(_5\backslash0a\ bb\)
0, 5
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 1 |
1 | bbab\0a | 5 |
2 | bab\0ab | 4 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0ab\ ba\)
1, 4
\(_1bb\ ab\)
5, 1
\(_2ba\ b\backslash0\)
4, 3
\(_3ab\ \backslash0a\)
1, 0
\(_4b\backslash0\ ab\)
3, 1
\(_5\backslash0a\ bb\)
0, 5
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 1 |
1 | bbab\0a | 5 |
2 | bab\0ab | 4 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0abba\)
2
\(_1bbab\)
5
\(_2bab\backslash0\)
4
\(_3ab\backslash0a\)
1
\(_4b\backslash0ab\)
3
\(_5\backslash0abb\)
0
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 2 |
1 | bbab\0a | 5 |
2 | bab\0ab | 4 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0abba\)
2
\(_1bbab\)
5
\(_2bab\backslash0\)
4
\(_3ab\backslash0a\)
1
\(_4b\backslash0ab\)
3
\(_5\backslash0abb\)
0
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 2 |
1 | bbab\0a | 5 |
2 | bab\0ab | 4 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0abba\ b\backslash0ab\)
2
\(_1bbab\ \backslash0abb\)
5
\(_2bab\backslash0\ abba\)
4
\(_3ab\backslash0a\ bbab\)
1
\(_4b\backslash0ab\ bab\backslash0\)
3
\(_5\backslash0abb\ ab\backslash0a\)
0
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 2 |
1 | bbab\0a | 5 |
2 | bab\0ab | 4 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0abbab\backslash0ab\)
2
\(_1bbab\backslash0abb\)
5
\(_2bab\backslash0abba\)
4
\(_3ab\backslash0abbab\)
1
\(_4b\backslash0abbab\backslash0\)
3
\(_5\backslash0abbab\backslash0a\)
0
Cyc | string | rank |
---|---|---|
0 | abbab\0 | 2 |
1 | bbab\0a | 5 |
2 | bab\0ab | 4 |
3 | ab\0abb | 1 |
4 | b\0abba | 3 |
5 | \0abbab | 0 |
\(_0abbab\backslash0ab\)
2
\(_1bbab\backslash0abb\)
5
\(_2bab\backslash0abba\)
4
\(_3ab\backslash0abbab\)
1
\(_4b\backslash0abbab\backslash0\)
3
\(_5\backslash0abbab\backslash0a\)
0
將每個字串往後抄
目前長度個字元
把兩段字串分別用\(rank\)值表示
弄出一個\(pair\)
利用\(pair\)排序
把新的\(rank\)抄回去
將每個字串往後抄
目前長度個字元
把兩段字串分別用\(rank\)值表示
弄出一個\(pair\)
利用\(pair\)排序
把新的\(rank\)抄回去
總共要繞\(\log n\)圈
將每個字串往後抄
目前長度個字元
把兩段字串分別用\(rank\)值表示
弄出一個\(pair\)
利用\(pair\)排序
把新的\(rank\)抄回去
總共要繞\(\log n\)圈
\(\Omicron(n)\)
\(\Omicron(n\log n)\)
\(\Omicron(n)\)
將每個字串往後抄
目前長度個字元
把兩段字串分別用\(rank\)值表示
弄出一個\(pair\)
利用\(pair\)排序
把新的\(rank\)抄回去
總共要繞\(\log n\)圈
\(\Omicron(n)\)
\(\Omicron(n\log n)\)
\(\Omicron(n)\)
總複雜度\(\Omicron(n\log^2n)\)
struct P {
pii p;
int id;
};
vector<int> SA(string s) {
int n = s.size();
vector<int> r(n + 1);
vector<P> v(n + 1);
vector<vector<P>> bar(n + 1);
function<bool(P, P)> cmp = [](P a, P b) {
return a.p < b.p;
};
function<void(void)> GetRank = [&]() {
for (int i = 0, j = 0; i <= n; i = j) {
while (j <= n && v[i].p == v[j].p) j++;
for (int k = i; k < j; k++) {
v[k].p.first = i;
r[v[k].id] = i;
}
}
};
for (int i = 0; i < n; i++) v[i] = {{s[i] - 'a' + 1, 0}, i};
v[n] = {{0, 0}, n};
sort(v.begin(), v.end(), [](P a, P b){return a.p < b.p;});
GetRank();
int len = 1;
while (len <= n) {
for (auto &i : v) i.p.second = r[(i.id + len) % (n + 1)];
sort(v.begin(), v.end(), cmp);
GetRank();
len <<= 1;
}
return r;
}
排序下列數字:
\(\{41,78,38,57,59,50,72,43,46,61\}\)
排序下列數字:
\(\{41,78,38,57,59,50,72,43,46,61\}\)
0 | |||
1 | |||
2 | |||
3 | |||
4 | |||
5 | |||
6 | |||
7 | |||
8 | |||
9 |
排序下列數字:
\(\{41,78,38,57,59,50,72,43,46,61\}\)
0 | 50 | ||
1 | 41 | 61 | |
2 | 72 | ||
3 | 43 | ||
4 | |||
5 | |||
6 | 46 | ||
7 | 57 | ||
8 | 78 | 38 | |
9 | 59 |
\(\{41,78,38,57,59,50,72,43,46,61\}\)
\(\Rightarrow\{50,41,61,72,43,46,57,78,38,59\}\)
0 | 50 | ||
1 | 41 | 61 | |
2 | 72 | ||
3 | 43 | ||
4 | |||
5 | |||
6 | 46 | ||
7 | 57 | ||
8 | 78 | 38 | |
9 | 59 |
\(\{41,78,38,57,59,50,72,43,46,61\}\)
\(\Rightarrow\{50,41,61,72,43,46,57,78,38,59\}\)
0 | |||
1 | |||
2 | |||
3 | |||
4 | |||
5 | |||
6 | |||
7 | |||
8 | |||
9 |
\(\{41,78,38,57,59,50,72,43,46,61\}\)
\(\Rightarrow\{50,41,61,72,43,46,57,78,38,59\}\)
0 | |||
1 | |||
2 | |||
3 | 38 | ||
4 | 41 | 43 | 46 |
5 | 50 | 57 | 59 |
6 | 61 | ||
7 | 72 | 78 | |
8 | |||
9 |
\(\{41,78,38,57,59,50,72,43,46,61\}\)
\(\Rightarrow\{50,41,61,72,43,46,57,78,38,59\}\)
\(\Rightarrow\{38,41,43,46,50,57,59,61,72,78\}\)
0 | |||
1 | |||
2 | |||
3 | 38 | ||
4 | 41 | 43 | 46 |
5 | 50 | 57 | 59 |
6 | 61 | ||
7 | 72 | 78 | |
8 | |||
9 |
將每個字串往後抄
目前長度個字元
把兩段字串分別用\(rank\)值表示
弄出一個\(pair\)
利用\(pair\)排序
把新的\(rank\)抄回去
總共要繞\(\log n\)圈
\(\Omicron(n)\)
\(\Omicron(n\log n)\)
\(\Omicron(n)\)
將每個字串往後抄
目前長度個字元
把兩段字串分別用\(rank\)值表示
弄出一個\(pair\)
利用\(pair\)排序
把新的\(rank\)抄回去
總共要繞\(\log n\)圈
\(\Omicron(n)\)
\(\Omicron(n)\)
\(\Omicron(n)\)
將每個字串往後抄
目前長度個字元
把兩段字串分別用\(rank\)值表示
弄出一個\(pair\)
利用\(pair\)排序
把新的\(rank\)抄回去
總共要繞\(\log n\)圈
\(\Omicron(n)\)
\(\Omicron(n)\)
\(\Omicron(n)\)
總複雜度\(\Omicron(n\log n)\)
struct P {
pii p;
int id;
};
vector<int> SA(string s) {
int n = s.size();
vector<int> r(n + 1);
vector<P> v(n + 1);
vector<vector<P>> bar(n + 1);
function<void(void)> RS = [&]() {
for (auto &i : v) bar[i.p.second].push_back(i);
for (int i = 0, j = 0; i <= n; i++) {
for (auto &k : bar[i]) v[j++] = k;
bar[i].clear();
}
for (auto &i : v) bar[i.p.first].push_back(i);
for (int i = 0, j = 0; i <= n; i++) {
for (auto &k : bar[i]) v[j++] = k;
bar[i].clear();
}
};
function<void(void)> GetRank = [&]() {
for (int i = 0, j = 0; i <= n; i = j) {
while (j <= n && v[i].p == v[j].p) j++;
for (int k = i; k < j; k++) {
v[k].p.first = i;
r[v[k].id] = i;
}
}
};
for (int i = 0; i < n; i++) v[i] = {{s[i] - 'a' + 1, 0}, i};
v[n] = {{0, 0}, n};
sort(v.begin(), v.end(), [](P a, P b){return a.p < b.p;});
GetRank();
int len = 1;
while (len <= n) {
for (auto &i : v) i.p.second = r[(i.id + len) % (n + 1)];
RS();
GetRank();
len <<= 1;
}
return r;
}
\(LCP(abbab,abab)=2\)
\(abbab\)
\(abab\)
生出一個資料結構,可以幫我們查詢任意兩組後綴的LCP
生出一個資料結構,可以幫我們查詢任意兩組後綴的LCP
\(s=abbab\backslash0\)
\(S_s[0]=\backslash0\)
\(S_s[1]=b\backslash0\)
\(S_s[2]=ab\backslash0\)
\(S_s[3]=bab\backslash0\)
\(S_s[4]=bbab\backslash0\)
\(S_s[5]=abbab\backslash0\)
\(LCP_s(1,4)\)
\(=LCP(b,bbab)\)
\(=1\)
生出一個資料結構,可以幫我們查詢任意兩組後綴的LCP
好啦我們還是比較喜歡\(cycle\)
生出一個資料結構,可以幫我們查詢任意兩個\(cycle\)的LCP
生出一個資料結構,可以幫我們查詢任意兩個\(cycle\)的LCP
\(s=abbab\backslash0\)
\(s.cycle(0)=abbab\backslash0\)
\(s.cycle(1)=bbab\backslash0a\)
\(s.cycle(2)=bab\backslash0ab\)
\(s.cycle(3)=ab\backslash0abb\)
\(s.cycle(4)=b\backslash0abba\)
\(s.cycle(5)=\backslash0abbab\)
\(LCP_s(4,1)\)
\(=LCP(b\backslash0abba,bbab\backslash0a)\)
\(=1\)
還記得剛剛的\(rank\)陣列嗎
string | a | b | b | a | b | \0 |
rank | 1 | 3 | 3 | 1 | 3 | 0 |
string | ab | bb | bb | ab | b\0 | \0a |
rank | 1 | 5 | 4 | 1 | 3 | 0 |
string | abba | bbab | bab\0 | ab\0a | b\0ab | \0abb |
rank | 2 | 5 | 4 | 1 | 3 | 0 |
string | 放 | 不 | 下 | 了 | ... | ... |
rank | 2 | 5 | 4 | 1 | 3 | 0 |
但是空間複雜度呢?
\(S_s[5]=\backslash0\)
\(S_s[3]=ab\backslash0\)
\(S_s[0]=abbab\backslash0\)
\(S_s[4]=b\backslash0\)
\(S_s[2]=bab\backslash0\)
\(S_s[1]=bbab\backslash0\)
\(s=abbab\)
我們開一個陣列\(l\)
使得\(l[i]=\)排名在第\(i\)的後綴和排名在第\(i+1\)的後綴做\(LCP\)
\(S_s[5]=\backslash0\)
\(S_s[3]=ab\backslash0\)
\(S_s[0]=abbab\backslash0\)
\(S_s[4]=b\backslash0\)
\(S_s[2]=bab\backslash0\)
\(S_s[1]=bbab\backslash0\)
\(s=abbab\)
我們開一個陣列\(l\)
使得\(l[i]=\)排名在第\(i\)的後綴和排名在第\(i+1\)的後綴做\(LCP\)
\(l[0]=0\)
\(l[1]=2\)
\(l[2]=0\)
\(l[3]=1\)
\(l[4]=1\)
\(S_s[5]=\backslash0\)
\(S_s[3]=ab\backslash0\)
\(S_s[0]=abbab\backslash0\)
\(S_s[4]=b\backslash0\)
\(S_s[2]=bab\backslash0\)
\(S_s[1]=bbab\backslash0\)
\(l[0]=0\)
\(l[1]=2\)
\(l[2]=0\)
\(l[3]=1\)
\(l[4]=1\)
如果我想要找\(LCP(S_s[3],S_s[2])\)
\(S_s[5]=\backslash0\)
\(S_s[3]=ab\backslash0\)
\(S_s[0]=abbab\backslash0\)
\(S_s[4]=b\backslash0\)
\(S_s[2]=bab\backslash0\)
\(S_s[1]=bbab\backslash0\)
\(l[0]=0\)
\(l[1]=2\)
\(l[2]=0\)
\(l[3]=1\)
\(l[4]=1\)
如果我想要找\(LCP(S_s[3],S_s[2])\)
答案會是\(\min(l[1\dots4])\)
找\(LCP\)會變成求區間最小值(RMQ)
拿棵線段樹什麼的維護\(l\)就好了
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=?\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]=?\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=?\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]=?\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=?\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]=?\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=?\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]=?\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=?\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]=?\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]=?\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]=?\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]=?\)
\(LCP(S_s[0],S_s[3])=2\)
\(\Rightarrow LCP(S_s[1],S_s[4])=1\)
\(\Rightarrow LCP(S_s[1],S_s[2])\geq1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]\geq1\)
\(LCP(S_s[0],S_s[3])=2\)
\(\Rightarrow LCP(S_s[1],S_s[4])=1\)
\(\Rightarrow LCP(S_s[1],S_s[2])\geq1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]\geq1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]=1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]=1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=?\)
\(l[4]=1\)
\(LCP(S_s[1],S_s[2])=1\)
\(\Rightarrow LCP(S_s[2],S_s[3])=0\)
\(\Rightarrow LCP(S_s[2],S_s[4])\geq0\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]\geq0\)
\(l[4]=1\)
\(LCP(S_s[1],S_s[2])=1\)
\(\Rightarrow LCP(S_s[2],S_s[3])=0\)
\(\Rightarrow LCP(S_s[2],S_s[4])\geq0\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]\geq0\)
\(l[4]=1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]\geq0\)
\(l[4]=1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=1\)
\(l[4]=1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=?\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=1\)
\(l[4]=1\)
\(LCP(S_s[2],S_s[4])=1\)
\(\Rightarrow LCP(S_s[3],S_s[5])=0\)
\(\Rightarrow LCP(S_s[3],S_s[5])\geq0\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]\geq0\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=1\)
\(l[4]=1\)
\(LCP(S_s[2],S_s[4])=1\)
\(\Rightarrow LCP(S_s[3],S_s[5])=0\)
\(\Rightarrow LCP(S_s[3],S_s[5])\geq0\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]\geq0\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=1\)
\(l[4]=1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=0\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=1\)
\(l[4]=1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=0\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=1\)
\(l[4]=1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=0\)
\(l[1]=2\)
\(l[2]=?\)
\(l[3]=1\)
\(l[4]=1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=0\)
\(l[1]=2\)
\(l[2]=0\)
\(l[3]=1\)
\(l[4]=1\)
\(s=abbab\)
\(_50\)
\(_3ab0\)
\(_0abbab0\)
\(_4b0\)
\(_2bab0\)
\(_1bbab0\)
\(l[0]=0\)
\(l[1]=2\)
\(l[2]=0\)
\(l[3]=1\)
\(l[4]=1\)
其實是懶得寫證明
vector<int> LCP(string s, vector<int> &r) {
int n = s.size();
vector<int> p(n + 1), l(n);
for (int i = 0; i <= n; i++) p[r[i]] = i;
int len = 0;
for (int i = 0; i < n; i++) {
int j = p[r[i] - 1];
while (i + len < n && j + len < n && s[i + len] == s[j + len]) len++;
l[r[i] - 1] = len;
if (len) len--;
}
return l;
}
各種毒瘤延伸: