CodeForces - 1494C 1D Sokoban(思维)
题目大意
你站在0的位置向左右推箱子,如果推的箱子与另一个箱子相邻,那么另一个箱子会一起移动,不能将箱子拉向自己,然后有几个特殊位置,问最多能将多少个箱子推到特殊位置上。
解题思路
把位置是正数和负数的箱子分开处理。枚举第一个箱子推到每个特殊位置时候的情况,然后再计算出连在一起的箱子(因为一直往右推,所以这个数量是单调的),再计算出这些连续的箱子中有几个是特殊位置然后加上剩下区间的在特殊位置的箱子数就行了。思路不难,主要是实现。
代码
const int maxn = 2e5+10;
const int maxm = 2e5+10;
int n, m;
int a[maxn], b[maxn], pre[maxn];
int solve1() {
int p = 0;
for (int i = 1; i<=n; ++i)
if (a[i]>=0) {
p = i;
break;
}
if (!p) return 0;
int r = p, res = 0;
for (int i = 1; i<=m; ++i)
if (b[i]>=a[p]) {
while(r+1<=n && a[r+1]<=b[i]+r-p+1) ++r;
int tmp = upper_bound(b+1, b+m+1, b[i]+r-p)-b-i;
res = max(res, tmp+pre[n]-pre[r]);
}
return res;
}
int solve2() {
int p = 0;
for (int i = n; i>=1; --i)
if (a[i]<0) {
p = i;
break;
}
if (!p) return 0;
int l = p, res = 0;
for (int i = m; i>=1; --i)
if (b[i]<=a[p]) {
while(l-1>=1 && a[l-1]>=b[i]-(p-l+1)) --l;
int tmp = i-(lower_bound(b+1, b+m+1, b[i]-(p-l))-b)+1;
res = max(res, tmp+pre[l-1]);
}
return res;
}
int main() {
int __; cin >> __;
while(__--) {
cin >> n >> m;
for (int i = 1; i<=n; ++i) cin >> a[i];
for (int i = 1; i<=m; ++i) cin >> b[i];
for (int i = 1; i<=n; ++i) {
pre[i] = 0;
int pos = lower_bound(b+1, b+m+1,a[i])-b;
if (pos>=1 && pos<=m && b[pos]==a[i]) ++pre[i];
pre[i] += pre[i-1];
}
int ans = solve1();
ans += solve2();
cout << ans << endl;
}
return 0;
}