luogu P4696 [CEOI2011]Matching
luogu P4696 [CEOI2011]Matching
题目大意
讲得比较清楚了吧
我就讲怎么把问题转换吧
p
[
i
]
p[i]
p[i]表示的是排名为
i
i
i的在第
p
[
i
]
p[i]
p[i]那个位置
然后我们可以令
r
k
[
i
]
rk[i]
rk[i]表示第
i
i
i位的排名位
r
k
[
i
]
rk[i]
rk[i],很明显
r
k
[
p
[
i
]
]
=
i
rk[p[i]] = i
rk[p[i]]=i
然后就转换为
r
k
rk
rk数组和
a
a
a进行匹配了
考虑怎么匹配,
令
p
r
e
[
i
]
表
示
r
k
[
i
]
在
r
k
[
1....
i
]
中
的
排
名
pre[i]表示 \ \ \ \ \ rk[i] 在 rk[1....i]中的排名
pre[i]表示 rk[i]在rk[1....i]中的排名,然后那个树状数组维护一下就可以把pre搞出来了
然后再用KMP求
n
x
t
nxt
nxt
最后把
a
a
a丢进去匹配就行了,过程和普通的差不多
来看代码ba
code:
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define lowbit(x) (x & -x)
#define N 1000005
using namespace std;
int tree[N];
void update(int x, int y){
for(;x < N; x += lowbit(x)) tree[x] += y;
}
int query(int x){
int ret = 0;
for(;x; x -= lowbit(x)) ret += tree[x];
return ret;
}
int n, m, a[N], rk[N], nxt[N], pre[N], c[N], b[N], ans[N];
int main(){
scanf("%d%d", &n ,&m);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), rk[a[i]] = i;//转换为rk
for(int i = 1; i <= n; i ++)
pre[i] = query(rk[i]), update(rk[i], 1);//转换为pre
pre[n + 1] = -1;//方便下面的匹配
memset(tree, 0, sizeof tree);
int j = 0;
for(int i = 1; i < n; i ++){//造nxt
while(j && pre[j + 1] != query(rk[i + 1])){
for(int k = i - j + 1; k <= i - nxt[j]; k ++)
update(rk[k], -1);
j = nxt[j];
}
if(pre[j + 1] == query(rk[i + 1])) j ++, update(rk[i + 1], 1);
nxt[i + 1] = j;
}
for(int i = 1; i <= m; i ++) scanf("%d", &b[i]), c[i] = b[i];
sort(c + 1, c + 1 + m);
for(int i = 1; i <= m; i ++) b[i] = lower_bound(c + 1, c + 1 + m, b[i]) - c;//把a离散化
j = 0;
memset(tree, 0, sizeof tree);
for(int i = 0; i < m; i ++){//匹配
while(j && pre[j + 1] != query(b[i + 1])){//看对应的排名是否相同
for(int k = i - j + 1; k <= i - nxt[j]; k ++)//不相同就往前跳,记得把失配那一段的从树状数组中清掉,否则会影响排名
update(b[k], -1);
j = nxt[j];//往前跳
}
if(pre[j + 1] == query(b[i + 1])) j ++, update(b[i + 1], 1);//匹配就匹配
if(j == n) ans[++ ans[0]] = i - n + 2;//匹配到了就记录答案,不用往前跳因为之前已经把pre[n+1]设为-1了,所以下一轮会跳
}
printf("%d\n", ans[0]);
for(int i = 1; i <= ans[0]; i ++) printf("%d ", ans[i]);//输出
return 0;
}
总结
不得不说这真是道KMP好题,写完这题对KMP的认识又深了一个层次
问题一步一步的转换,然后分析,完全不是死套模板,是道思博锻炼思维的题目。
学习一个东西还是不能死套模板,而是要理解里面的原理,巧妙利用和变化。