倒垃圾(思维题)

题意

一条街道可以看作一个数轴。街道上住着\(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;
}
posted @ 2022-06-12 10:37  pbc的成长之路  阅读(77)  评论(0编辑  收藏  举报