int z[N]; voidz_algorithm(constchar *s){ // 下标从 1 开始 int l = 0, r = 0; int n = strlen(s + 1); for(int i = 2; i <= n; i++) { if(i <= r) z[i] = std::min(z[i - l + 1], r - i + 1); while(i + z[i] <= n && s[i + z[i]] == s[z[i] + 1]) z[i]++; if(i + z[i] > r) l = i, r = i + z[i] - 1; } }
应用
例题 1
给出两个字符串 s, t,求出所有的位置 x,满足 \(s[x .. x + len(t) - 1] = t\)。 其中 \(len(s), len(t) \le 10^5\),s, t 仅包含大小写字母。
也可以按照 Z 算法类似的方式直接算。(设 \(e(i)\) 表示满足 \(s[i .. i + x - 1] = t[1 .. x]\) 的最大的 \(x\))
代码
1 2 3 4 5 6 7 8 9 10
int e[N]; voidexkmp(constchar *s, constchar *t){ // 下标从 1 开始 int l = 0, r = 0; int n = strlen(s + 1); for(int i = 2; i <= n; i++) { if(i <= r) e[i] = std::min(z[i - l + 1], r - i + 1); while(i + e[i] <= n && s[i + e[i]] == t[e[i] + 1]) e[i]++; if(i + e[i] > r) l = i, r = i + e[i] - 1; } }
int z[N]; voidz_algorithm(constchar *s){ // 下标从 1 开始 int l = 0, r = 0; int n = strlen(s + 1); for(int i = 2; i <= n; i++) { if(i <= r) z[i] = std::min(z[i - l + 1], r - i + 1); while(i + z[i] <= n && s[i + z[i]] == s[z[i] + 1]) z[i]++; if(i + z[i] > r) l = i, r = i + z[i] - 1; } }
int e[N]; voidexkmp(constchar *s, constchar *t){ // 下标从 1 开始 int l = 0, r = 0; int n = strlen(s + 1); for(int i = 2; i <= n; i++) { if(i <= r) e[i] = std::min(z[i - l + 1], r - i + 1); while(i + e[i] <= n && s[i + e[i]] == t[e[i] + 1]) e[i]++; if(i + e[i] > r) l = i, r = i + e[i] - 1; } }
intmain(){ scanf("%s%s", a + 1, b + 1); int la = strlen(a + 1), lb = strlen(b + 1); z_algorithm(b); z[1] = lb; LL ans = 0; for(int i = 1; i <= lb; i++) ans ^= (LL)i * (z[i] + 1); printf("%lld\n", ans); exkmp(a, b); for(int i = 1; i <= lb; i++) if(a[i] == b[i]) e[1] = i; elsebreak; ans = 0; for(int i = 1; i <= la; i++) ans ^= (LL)(i) * (e[i] + 1); printf("%lld\n", ans); return0; }