W
h
y
D
i
d
t
h
e
C
o
w
C
r
o
s
s
t
h
e
R
o
a
d
Why\ Did\ the\ Cow\ Cross\ the\ Road
Why Did the Cow Cross the Road
题目描述见链接 .
正
解
部
分
\color{red}{正解部分}
正解部分
设
F
[
i
,
j
]
F[i, j]
F[i,j] 表示
A
A
A 序列前
i
i
i 项,
B
B
B 序列前
j
j
j 项 的最大匹配数,
i
,
j
i,j
i,j 不相连:
F
[
i
,
j
]
=
max
(
F
[
i
−
1
,
j
]
,
F
[
i
,
j
−
1
]
)
F[i, j] = \max(F[i-1,j],F[i,j-1])
F[i,j]=max(F[i−1,j],F[i,j−1])
i
,
j
i, j
i,j 相连:
F
[
i
,
j
]
=
max
(
F
[
i
−
1
,
j
−
1
]
+
1
)
F[i, j] = \max(F[i-1,j-1]+1)
F[i,j]=max(F[i−1,j−1]+1)
经典的最长公共子序列算法 .
考虑优化, 发现
i
i
i 与
j
j
j 相连当且仅当
∣
A
i
−
B
j
∣
≤
4
|A_i-B_j| \le 4
∣Ai−Bj∣≤4, 于是在
i
i
i 确定的情况下,
j
j
j 最多只有
9
9
9 个可能的取值,
所以可以记下
B
j
B_j
Bj 的位置
p
o
s
B
j
pos_{B_j}
posBj 从小到大枚举
i
i
i, 再枚举
9
9
9 种可能的
B
j
B_j
Bj, 从
F
[
i
−
1
,
0
.
.
.
p
o
s
B
j
−
1
−
1
]
+
1
F[i-1, 0 \ ...\ pos_{B_j-1}-1]+1
F[i−1,0 ... posBj−1−1]+1 转移过来, 使用 树状数组 优化 最大前缀 即可实现
O
(
9
×
N
log
N
)
O(9\times N \log N)
O(9×NlogN) .
实
现
部
分
\color{red}{实现部分}
实现部分
#include<bits/stdc++.h>
#define reg register
const int maxn
= 100005;
int N
;
int A
[maxn
];
int B
[maxn
];
int tmp
[maxn
];
int pos
[maxn
];
struct Bit_Tree
{
int v
[maxn
], lim
;
void Add(int k
, int x
){
while(k
<= lim
){
v
[k
] = std
::max(v
[k
], x
);
k
+= k
&-k
;
}
}
int Query(int k
){
if(k
<= 0) return 0;
int s
= 0;
while(k
){
s
= std
::max(s
, v
[k
]);
k
-= k
&-k
;
}
return s
;
}
} bit_t
;
int main(){
scanf("%d", &N
);
for(reg
int i
= 1; i
<= N
; i
++) scanf("%d", &A
[i
]);
for(reg
int j
= 1; j
<= N
; j
++) scanf("%d", &B
[j
]), pos
[B
[j
]] = j
;
bit_t
.lim
= N
;
for(reg
int i
= 1; i
<= N
; i
++){
int dlim
= std
::max(1, A
[i
]-4), ulim
= std
::min(N
, A
[i
]+4);
for(reg
int j
= dlim
; j
<= ulim
; j
++) tmp
[j
] = bit_t
.Query(pos
[j
]-1) + 1;
for(reg
int j
= dlim
; j
<= ulim
; j
++) bit_t
.Add(pos
[j
], tmp
[j
]);
}
printf("%d\n", bit_t
.Query(N
));
return 0;
}