Description
你两个字符串s[1..n],t[1..m],每次给一个st,询问子串s[st..n]与t的最长公共前缀。
Input
第一行一个字符串s,第二行一个字符串t,
第三行一个数q表示询问数,接下来q行每行一个整数st。
Output
对于每次询问输出一行一个整数表示最长前缀长度。
abaab
abbbaab
5
1
2
3
4
5
-
Sample Input
2
0
1
2
0
-
Sample Output
HINT
n,m≤1000000 q≤1000000
Uploaded By MCHacker
EXJKMP裸题
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 1000010;
int nxt[MAXN], ext[MAXN]; char s[MAXN], t[MAXN];
void get_next() { // 求出next数组
int lt=strlen(t);
nxt[0] = lt; int i = 0; // 显然next[0]为t的长度
while ((t[i]==t[i+1]) && (i+1<lt)) ++i; // 第一个直接暴力
nxt[1] = i;
int p0=1;
for (int i=2; i<lt; ++i) {
if (i+nxt[i-p0]<p0+nxt[p0]) nxt[i] = nxt[i-p0]; // 显然不能再扩展,直接求出
else {
int j = max(0, nxt[p0]+p0-i);
while ((i+j<lt) && (t[j]==t[i+j])) ++j; // 又是暴力
nxt[i] = j; if (i+nxt[i]>p0+nxt[p0]) p0=i; // 更新p0
}
}
}
void get_extend() { // 求结果,似乎和jext差不多
int ls=strlen(s), lt=strlen(t); int i = 0;
while ((s[i]==t[i]) && (i<ls) && (i<lt)) ++i;
ext[0] = i;
int p0=0;
for (int i=1; i<ls; ++i) {
if (i+nxt[i-p0]<p0+ext[p0]) ext[i] = nxt[i-p0];
else {
int j = max(0, ext[p0]+p0-i);
while ((i+j<ls) && (j<lt) && (t[j]==s[i+j])) ++j;
ext[i] = j; if (i+ext[i]>p0+ext[p0]) p0=i;
}
}
}
int main() {
scanf("%s%s", s, t);
int q; scanf("%d", &q);
get_next(); get_extend();
while (q--) {
int x; scanf("%d", &x);
printf("%d\n", ext[x-1]);
}
return 0;
}