倒垃圾(思维题)
题意
一条街道可以看作一个数轴。街道上住着\(n\)个居民并设有\(m\)个垃圾桶,每个居民的住所或垃圾桶占据一个位置。已知,这\(n+m\)个位置两两不同。
每个居民每天都会前往距离自己家最近的垃圾桶处倒垃圾。如果这样的垃圾桶不唯一,则居民会优先选择前往位置坐标更小的垃圾桶处倒垃圾。
请你计算,对于每个垃圾桶,每天有多少居民在该垃圾桶处倒垃圾。
题目链接:https://www.acwing.com/problem/content/4483/
数据范围
\(1 \leq n, m \leq 10^5\)
思路
这道题我最初的方法有些麻烦,就是先预处理出所有垃圾桶的位置。然后对于每个居民,通过二分查找得到距离最近的前后两个垃圾桶。
现在分享一个更简洁的做法。从前向后扫描序列,预处理距离每个居民最近的前一个垃圾桶;再从后向前扫描序列,预处理距离每个居民最近的后一个垃圾桶。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 200010;
int n, m;
int a[N], t[N];
int pre[N], suf[N];
int ans[N];
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n + m; i ++) scanf("%d", &a[i]);
for(int i = 1; i <= n + m; i ++) scanf("%d", &t[i]);
int last = -1;
for(int i = 1; i <= n + m; i ++) {
if(!t[i]) pre[i] = last;
else last = i;
}
last = -1;
for(int i = n + m; i >= 1; i --) {
if(!t[i]) suf[i] = last;
else last = i;
}
for(int i = 1; i <= n + m; i ++) {
if(!t[i]) {
if(pre[i] == -1) ans[suf[i]] ++;
else if(suf[i] == -1) ans[pre[i]] ++;
else {
if(a[i] - a[pre[i]] <= a[suf[i]] - a[i]) ans[pre[i]] ++;
else ans[suf[i]] ++;
}
}
}
for(int i = 1; i <= n + m; i ++) {
if(t[i]) {
printf("%d ", ans[i]);
}
}
printf("\n");
return 0;
}