字符串相关
这个部分放置的是与字符串相关的版子
5. 7
字典树
// 字典树trie
struct trie{
static const int N = 1e6 + 100;
int mp[N][30];
int e[N];
int cnt = 1;
// 字典树建立
void build(string s, int len){
int p = 0;
for(int i = 0; i < len; i++){
int c = s[i] - 'a';
if(mp[p][c] == 0)
mp[p][c] = cnt++;
p = mp[p][c];
}
e[p]++;
}
// 字典树查询
int query(string s, int len){
int p = 0;
for(int i = 0; i < len; i++){
int c = s[i] - 'a';
if(mp[p][c] == 0)
return false;
p = mp[p][c];
}
return e[p];
}
} Trie;
AC自动机(加了拓扑排序优化)
// AC自动机
namespace AC{
static const int N = 1e6 + 100;
//mp是字典树,e是表明结点是不是模式串结尾结点
//cnt是结点个数
//fail是AC自动机的失配指针
//表示的状态是当前状态的在字典树上的最长后缀的状态
//idx是编号为下标所指的模式串的结尾结点
//in是按照fail指针所建立有向边,结点的入度
int mp[N][30], e[N], res[N], cnt = 0, fail[N], idx[N], in[N];
// 字典树建立
void Insert(string s, int len, int id){
int p = 0;
for(int i = 0; i < len; i++){
int c = s[i] - 'a';
if(mp[p][c] == 0)
mp[p][c] = ++cnt;
p = mp[p][c];
}
e[p] = 1;
idx[id] = p;
}
//建立fail
void build(){
queue <int> q;
for(int i = 0 ; i < 26; i ++)
if(mp[0][i])
q.push(mp[0][i]);
while(!q.empty()){
int p = q.front();
q.pop();
for(int i = 0; i < 26; i++){
if(mp[p][i]){
fail[mp[p][i]] = mp[fail[p]][i], q.push(mp[p][i]), in[fail[mp[p][i]]]++;
}
else
mp[p][i] = mp[fail[p]][i];
}
}
}
//查询
void query(string s, int len){
int p = 0;
int ans = 0;
for(int i = 0 ; i < len; i++){
int c = s[i] - 'a';
p = mp[p][c];
res[p]++;
}
// return ans;
}
// 拓扑排序优化
void topu(int n){
queue<int> q;
for(int i = 1; i <= cnt; i++)
if(in[i] == 0)
q.push(i);
while(!q.empty()){
int k = q.front();
q.pop();
int u = fail[k];
res[u] += res[k];
in[u]--;
if(in[u] == 0)
q.push(u);
}
}
}
5.8
KMP
namespace KMP{
static const int N = 1e6 + 100;
int next[N];
void cal_next(string s, int len){
next[0] = -1;
int k = -1;
for(int i = 1; i < len; i++){
while(k > -1 && s[k + 1] != s[i])
k = next[k];
if(s[k + 1] == s[i])
k = k + 1;
next[i] = k;
}
}
int find(string s, int lens, string p, int lenp){
int k = -1;
cal_next(p, lenp);
for(int i = 0; i < lens; i++){
while(k > -1 && p[k + 1] != s[i])
k = next[k];
if(p[k + 1] == s[i])
k = k + 1;
if(k == lenp - 1){
//寻找下一个位置
cout << i - lenp + 2 << '\n';
k = next[k];
//return i - lenp + 1;
}
}
return -1;
}
}
5.11
扩展KMP
namespace EX_KMP{
typedef long long ll;
const int N = 2e7 + 100;
// next是要匹配的模式串的所有后缀和自身的最长公共前缀长度
// exi是匹配串的所有后缀和模式串的最长公共前缀长度
ll next[N], exi[N];
void cal_next(string s, int len){
int k = 1, p = 0, l;
next[0] = len;
while(p + 1 < len && s[p] == s[p + 1]) p++;
next[1] = p;
for(int i = 2; i < len; i++){
p = k + next[k] - 1;
l = next[i - k];
if(i + l <= p)
next[i] = l;
else{
int j = max(0, p - i + 1);
while(i + j < len && s[i + j] == s[j]) j++;
next[i] = j;
k = i;
}
}
}
//要求出b中的每一个后缀和a的最长公共前缀
void cal_exi(string a, string b, int lena, int lenb){
int k = 0, p = 0, l;
while(p < lena && p < lenb && a[p] == b[p]) p++;
exi[0] = p;
for(int i = 1; i < lenb; i++){
p = k + exi[k] - 1;
l = next[i - k];
if(i + l <= p){
exi[i] = l;
}
else{
int j = max(0, p - i + 1);
while(i + j < lenb && j < lena && b[i + j] == a[j]) j++;
exi[i] = j;
k = i;
}
}
}
}