【二分+贪心】CF1665 C

68 篇文章 1 订阅
33 篇文章 0 订阅

Problem - C - Codeforces

题意:

 

思路:

一开始想太简单wa6了

只想到先感染大的分量,然后最后把最大的分量剩下的染色

但是可能会有别的分量更大(因为最后给最大的染色之后可能不再是最大的)

可以用堆维护,但是这里用二分做法

我们可以二分答案mid,问题就变成了mid秒内能否感染所有结点.

首先Injection一定用于优先感染兄弟结点比较多的结点,这样可以充分利用Spreading,我们可以结点按照兄弟的数量排序,然后优先感染兄弟多的结点.这样我们就知道了,第一秒被Injection的结点剩下的时间里可以被Spreading mid-1个兄弟,第二秒可以被Injection的结点可以被Spreading mid-2个兄弟,所以我们扫描一遍就可以知道还剩下多少个兄弟结点还没被感染,判断能否用剩下的Injection的操作将这些结点感染即可. 

Code:

#include <bits/stdc++.h>

using i64 = long long;

constexpr int N = 2e5 + 10;
constexpr int M = 2e5 + 10;
constexpr int mod = 998244353;

std::vector<int> adj[N];

int len = 0;
int a[N], b[N];

bool check(int mid) {
    int remain = 0;
    for (int i = 1, j = mid - 1; i <= len; i ++, j --) {
        remain += std::max(0,  b[i] - j);
    }
    return mid - len >= remain;
}
void solve() {
    int n;
    std::cin >> n;

    len = 1;
    for (int i = 1; i <= n; i ++) {
        adj[i].clear();
        b[i] = 0;
    }
    b[0] = 1;
    for (int i = 2; i <= n; i ++) {
        int x;
        std::cin >> x;
        adj[x].push_back(i);
    }

    for (int i = 1; i <= n; i ++) {
        if (adj[i].size()) {
            b[++len] = adj[i].size() - 1;
        }
    }

    std::sort(b + 1, b + 1 + len, std::greater<int>());

    int ans = 0;
    int l = 1, r = 1e9;
    while(l <= r) {
        int mid = l + r >> 1;
        if (check(mid)) {
            ans = mid;
            r = mid - 1;
        }else {
            l = mid + 1;
        }
    }

    std::cout << ans << "\n";
}
signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t = 1;
    std::cin >> t;
    while(t --) {
        solve();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值