Description
Input
Output
Sample Input
输入1:
7
1090901
4
87650
0901
109
090
输入2:
10
5821052680
4
210526
2105
582
105268
输入3:
3
001
1
11
Sample Output
输出1:
7
10
3
4
输出2:
8
6
3
9
输出3:
4
Data Constraint
20%的数据满足1<=N<=1000,1<=M<=500,单独一个添加剂序号的长度不超过1000
Hint
题目大意:
给两个字符串A,B,用B和A的每一个前缀一个个字符匹配,如果成功,则退出,否则一直匹配到结尾,对于当前匹配,如果当前字符不一样,就退出进入下一个前缀匹配,求匹配次数。
如果只求在哪一个位置匹配成功,那么是AC自动机的裸题,可惜并不是。
首先考虑不能匹配成功的,将A的后缀排序,对于B的每一个前缀,在排好序的A的后缀中二分出一个区间,使得这个区间的后缀全部能与B的这个前缀匹配,答案就是区间的长度和再加上n,因为还要加上没有匹配成功的那一次。
如果能匹配成功,匹配成功的位置是整个B串在A的后缀中二分出的区间内的后缀位置的最小值,设二分出的区间是l..r,匹配成功的位置就是最小的SA[l..r],这个可以通过RMQ解决。
我们得到了匹配成功的位置w,那么现在就是要求SA[l_i..r_i] <= w的个数,主席树可以完美处理这个问题。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,x,y) for(int i=x;i<=y;i++)
#define fd(i,x,y) for(int i=x;i>=y;i--)
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int Maxn = 100005;
char str[Maxn];
int T,n,m,len,ans,a[Maxn],b[Maxn];
int SA[Maxn],Height[Maxn],tax[Maxn],tp[Maxn],rank[Maxn];
int a2[17],fj[17][Maxn];
int g[Maxn],tot;
struct node {
int l, r, s;
}d[Maxn * 40];
int l[Maxn], r[Maxn];
void Init() {
scanf("%d\n", &n);
scanf("%s", str);
fo(i, 1, n) a[i] = str[i - 1];
}
bool cmp(int *f,int x,int y,int w) {return f[x] == f[y] && f[x + w] == f[y + w];}
void Rsort() {
fo(i, 1, m) tax[i] = 0;
fo(i, 1, n) tax[rank[tp[i]]] ++;
fo(i, 1, m) tax[i] += tax[i - 1];
fd(i, n, 1) SA[tax[rank[tp[i]]] --] = tp[i];
}
void Suffix() {
fo(i, 1, n) rank[i] = a[i], tp[i] = i;
m = 127, Rsort();
for(int w = 1, p = 1, i; p < n; w += w, m = p) {
for(p = 0, i = n - w + 1; i <= n; i ++) tp[++ p] = i;
fo(i, 1, n) if(SA[i] > w) tp[++ p] = SA[i] - w;
Rsort(), swap(rank, tp), rank[SA[1]] = p = 1;
fo(i, 2, n) rank[SA[i]] = cmp(tp, SA[i - 1], SA[i], w) ? p : ++ p;
}
int j, k = 0;
for(int i = 1; i <= n;Height[rank[i ++]] = k)
for( k = k ? k - 1 : k, j = SA[rank[i] - 1]; a[i + k] == a[j + k]; ++ k);
}
void build_multiplication() {
a2[0] = 1; fo(i, 1, 16) a2[i] = a2[i - 1] << 1;
fo(i, 1, n) fj[0][i] = SA[i];
fo(j, 1, 16) fo(i, 1, n) fj[j][i] = min(fj[j - 1][i], fj[j - 1][i + a2[j - 1]]);
}
int find_min(int x, int y) {
int lg = log2(y - x +1);
return min(fj[lg][x], fj[lg][y - a2[lg] + 1]);
}
void inc(int i, int x, int y, int w) {
if(x == y) d[i].s ++; else {
int m = (x + y) / 2;
if(w <= m) {
d[++ tot] = d[d[i].l], d[i].l = tot;
inc(d[i].l, x, m, w);
} else {
d[++ tot] = d[d[i].r], d[i].r = tot;
inc(d[i].r, m + 1, y, w);
}
d[i].s = d[d[i].l].s + d[d[i].r].s;
}
}
void build_time() {
g[0] = tot = 1;
fo(i, 1, n) {
d[++ tot] = d[g[i - 1]]; g[i] = tot;
inc(g[i], 1, n, rank[i]);
}
}
int find_sum(int i, int x, int y, int l, int r) {
if(i == 0) return 0;
if(l > r) return 0;
if(x == l && y == r) return d[i].s;
int m = (x + y) / 2;
if(r <= m) return find_sum(d[i].l, x, m, l, r);
if(l > m) return find_sum(d[i].r, m + 1, y, l, r);
return find_sum(d[i].l, x, m, l, m) + find_sum(d[i].r, m + 1, y, m + 1, r);
}
int cp(int st,int len) {
int i = st, j = 1;
for(;i <= n && j <= len; i ++, j ++) {
if(a[i] > b[j]) return 2;
if(a[i] < b[j]) return 0;
}
if(j > len) return 1;
return 0;
}
int erf(int x,int y,int z,int ex) {
int ans = z ? 0 : len + 1;
for(int l = x, r = y; l <= r;) {
int m = (l + r) / 2;
int bz = cp(SA[m], ex);
if(bz == 1) {
ans = m;
if(z) l = m + 1; else r = m - 1;
}
if(bz == 0) l = m + 1;
if(bz == 2) r = m - 1;
}
return ans;
}
void solution() {
scanf("%d", &T);
fo(cc, 1, T) {
ans = 0;
scanf("%s", str);
len = strlen(str);
fo(i, 0, len - 1) b[i + 1] = str[i];
l[0] = 1, r[0] = n;
fo(now, 1, len) {
l[now] = erf(l[now - 1], r[now - 1], 0, now);
r[now] = erf(l[now - 1], r[now - 1], 1, now);
}
int mm = l[len] <= r[len] ? find_min(l[len], r[len]) : n;
fo(now, 1, len) if(l[now] <= r[now]) {
ans += find_sum(g[mm], 1, n, l[now], r[now]);
}
ans += mm;
ans -= r[len] >= l[len];
printf("%d\n", ans);
}
}
int main() {
freopen("slasticar.in","r",stdin);
freopen("slasticar.out","w",stdout);
Init();
Suffix();
build_multiplication();
build_time();
solution();
}