CF729E 公司员工

1 CF729E 公司员工

2 题目描述

时间限制 \(1s\) | 空间限制 \(256M\)

公司有 \(n\) 个工人,编号从 \(1\)\(n\)。他们中间有一个编号是 \(s\) 的是主管。除了主管外每个工人都有一个直接上级。现在每个工人要说出自己有多少个上级(包括不是直接上级)。工人的直接上级也有直接上级,以此类推。例如如果公司有三个工人,第一个是主管,第二个的直接上级是第一个,第三个的直接上级是第二个。那么第三个有两个上级,有一个是直接上级,一个不是。主管是除了他本人以外所有人的上级。现在有些工人太着急了数错了,需要找出可能犯错误的最少工人数量。

数据范围:\(1 ≤ n ≤ 2\times 10^5, 1 ≤ s ≤ n\)

3 题解

根据题意容易发现,如果没有一个人有 \(i\) 个上级,那么一定没有人有大于 \(i\) 个上级。也就是说,我们必须保证所有的上级人数在排序后连续。如果一些人不是 \(s\) 且没有上级,那么这些人无论如何都是错的,答案就要加上这些人。由于我们只是要求最终构造出的序列连续,所以我们可以修改这些人的上级个数以弥补我们在构造过程中发现的不存在的上级人数。

但是如果这些人不够弥补所有的空缺,我们就要考虑从其他地方减少人数来弥补这些空缺。容易想到,如果我们从最大的上级人数开始取,我们一定是最优的。首先,取最大的上级人数并不会使原来连续的序列不再延续,因为最大的上级人数后面并没有其他人数对当前人数是否有人有要求。并且我们在减少了拥有最大上级人数的人数后,如果最大上级人数消失,那么可能使原来并不连续的序列变得连续。

4 代码(空格警告):

#include <iostream>
using namespace std;
const int N = 2e5+10;
int n, s, ans, rest, cnt;
int a[N], f[N];
int main()
{
    cin >> n >> s;
    for (int i = 1; i <= n; i++) cin >> a[i], f[a[i]]++;
    if (a[s] != 0)
    {
        f[a[s]]--;
        f[0]++;
        ans++;
    }
    rest = f[0]-1;
    ans += rest;
    cnt = n-1;
    while (!f[cnt]) cnt--;
    for (int i = 1; i < n; i++)
    {
        if (cnt <= i) break;
        if (!f[i] && rest)
        {
            rest--;
            f[i] = 1;
        }
        else if (!f[i])
        {
            while (!f[cnt]) cnt--;
            f[cnt]--;
            ans++;
            f[i] = 1;
            while (!f[cnt]) cnt--;
        }
    }
    cout << ans;
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-03-26 21:34  David24  阅读(39)  评论(0编辑  收藏  举报