【模板】KMP
\(KMP\)与前缀函数\(prefix(n)\)
#include <bits/stdc++.h>
using namespace std;
const int z = 65536;
int prefix[z];
void get_prefix(char *key) {
int l = strlen(key);
for(int i = 1, j;i < l;++i) {
j = prefix[i-1];
while(j > 0&&key[i] != key[j])
j = prefix[j-1];
if(key[i] == key[j]) ++j;
prefix[i] = j;
}
}//前缀函数计算;
int first_match(char *txt,char *key) {
get_prefix(key);
int len_key = strlen(key);
int len_txt = strlen(txt);
for(int i = 0, j = 0;i < len_txt;++i) {
while(j > 0&&txt[i] != key[j])
j = prefix[j];
if(txt[i] == key[j])
++j;
if(j == len_key)
return i-j+1;
}
return -1;
}//查询key在txt中的第一次出现;
int count_match(char *txt,char *key) {
get_prefix(key);
int ans = 0;
int len_key = strlen(key);
int len_txt = strlen(txt);
for(int i = 0, j = 0;i < len_txt;++i) {
while(j > 0&&txt[i] != key[j])
j = prefix[j];
if(txt[i] == key[j])
++j;
if(j == len_key) {
++ans;
j = prefix[j];
}
}
return ans;
}//查询key在txt中出现的次数;
char key[z], sig;
int KMP() {
sig = 32;
int i, j;
int ans = 0;
scanf("%s",key);
int len = strlen(key);
key[len++] = '#';
for(i = 1;i < len;++i) {
j = prefix[i-1];
while(j > 0&&key[i] != key[j])
j = prefix[j-1];
if(key[i] == key[j])
++j;
prefix[i] = j;
}
while(sig == 10||sig == 32)
sig = getchar();
for(;sig != 10&&sig != 32;sig = getchar()) {
while(j > 0&&sig != key[j])
j = prefix[j-1];
if(sig == key[j])
++j;
if(j == len-1)
ans++;
}
return ans;
}//KMP算法;
int round(char *key) {
get_prefix(key);
int len = strlen(key);
if(len%(len-prefix[len-1]) == 0)
return len-prefix[len-1];
else return 0;
}//字符串的周期;
int times[z];
void pre_times(char *key) {
get_prefix(key);
int len = strlen(key);
for(int i = 0;i < len;++i)
times[prefix[i]]++;
for(int i = len-1;i > 0;--i)
times[prefix[i-1]] += times[i];
for(int i = 0;i <= len;++i)
times[i]++;
}//每个前缀出现的次数;
signed main() {
//to do;
}
\(\text{优化的}KMP\text{自动机}\)
int prefixed[z];
void get_prefixed(char *pattern) {
int i = 1, j = -1;
int len = strlen(pattern);
prefixed[0] = -1;
for(;i < len;++i) {
while(j != -1&&pattern[i] != pattern[j+1])
j = prefixed[j];
if(pattern[i] == pattern[j+1])
++j;
if(j == -1||pattern[i+1] != pattern[j+1])
prefixed[i] = j;
else
prefixed[i] = prefixed[j];
}
}
char sig, pattern[z];
int KMP() {
sig = 32;
getstr(pattern);
int len = strlen(pattern), ans = 0, j = -1;
get_prefixed(pattern);
while(sig == 10||sig == 32)
sig = getchar();
for(;sig != 10&&sig != 32;sig = getchar()) {
while(j != -1&&sig != pattern[j+1])
j = prefixed[j];
if(sig == pattern[j+1])
++j;
if(j == len-1) {
ans++;
j = prefixed[j];
}
}
return ans;
}
注意这里的prefixed已经不是前缀数组了,而是更优跳转位置
麻了,KMP自动机打不过自动机,Kuguya真NB
最后define了getchar,到了16ms,赶过去了(
\(2022.06.08:redo\)
\(Z\ Algorithm\)与\(Z\)函数
int z[size];
void get_z(char *key) {
int len = strlen(key);
for(int i = 1, l = 0, r = 0;i < len;++i) {
if(i <= r&&z[i-l] < r-i+1)
z[i] = z[i-1];
else {
z[i] = max(0,r-i+1);
while(i+z[i] < len&&key[z[i]] == key[i+z[i]])
++z[i];
}
if(i+z[i]-1 > r) {
l = i;
r = i+z[i]-1;
}
}
}
#include "bits/stdc++.h"
using namespace std;
const int z = 1024;
char a[z], b[z];
int prefix[z];
void get_prefix(char *key) {
int l = strlen(key);
for(int i = 0, j;i < l;++i) {
j = prefix[i-1];
while(j > 0&&key[i] != key[j])
j = prefix[j-1];
//if match is failed,
//jump to the second length;
//After matching :
//if(success) key[i] == key[j] => prefix[i] = j+1;
//else j == 0 => prefix[i] = (key[i] == key[j]);
if(key[i] == key[j]) ++j;
prefix[i] = j;
}
}
int first_match(char *key,char *txt) {
int lk = strlen(key), lt = strlen(txt);
for(int i = 0, j = 0;i < lt;++i) {
while(j > 0&&txt[i] != key[j])
j = prefix[j];
if(txt[i] == key[j])
++j;
if(j == lk)
return i-j+1;
}
}
int count_match(char *key,char *txt) {
int ans = 0;
int lk = strlen(key), lt = strlen(txt);
for(int i = 0, j = 0;i < lt;++i) {
while(j > 0&&txt[i] != key[j])
j = prefix[j];
if(txt[i] == key[j])
++j;
if(j == lk) {
++ans;
j = prefix[j];
}
}
return ans;
}
int main() {
scanf("%s %s",a,b);
get_prefix(b);
printf("%d %d\n",first_match(b,a),count_match(b,a));
}