# 洛谷P4696 [CEOI2011]Matching（KMP）

## 题目大意

• $\{a\}$ 中任意两个数字互不相同；

• $(a_1,a_2,\cdots,a_n)$ 从小到大排序后，将会得到 $(a_{p_1},a_{p_2},\cdots,a_{p_n})$

## 解题思路

const int N = 1005000;
int rp[N], aft[N], pre[N], nxt[N], h[N], p[N], m, n;
bool cmp(int t, int *h, int x) {
if (aft[t] != n + 1 && x > h[rp[aft[t]]]) return 0;
if (pre[t] && x < h[rp[pre[t]]]) return 0;
return 1;
}

int ans[N], tp;
int main() {
for (int i = 1;i <= n; ++i) read(rp[i]), p[rp[i]] = i, pre[i] = i - 1, aft[i] = i + 1;
for (int i = n;i >= 1; --i) {
int nt = aft[p[i]], pr = pre[p[i]];
aft[pr] = nt, pre[nt] = pr;
}
int j = nxt[2] = 1;
for (int i = 3;i <= n; ++i) {
while (j && !cmp(p[j + 1], p + i - j - 1, p[i])) j = nxt[j];
if (cmp(p[j + 1], p + i - j - 1, p[i])) ++j;
nxt[i] = j;
}
j = 0;
for (int i = 1;i <= m; ++i) {
while (j && (j == n || !cmp(p[j + 1], h + i - j - 1, h[i]))) j = nxt[j];
if (cmp(p[j + 1], h + i - j - 1, h[i])) ++j;
if (j == n) ans[++tp] = i - n + 1;
}
write(tp);
for (int i = 1;i <= tp; ++i) write(ans[i], ' ');
return 0;
}

/*

5 10
1 2 5 3 4
1 8 9 6 4 45 32 88 2 7

*/

posted @ 2021-01-22 11:17  Hs-black  阅读(67)  评论(0编辑  收藏  举报