P10673 【MX-S1-T2】催化剂 题解

news/2024/10/9 15:00:41

要解决这个问题,我们需要高效地处理动态更新的糖果种类数量,并在每次询问时快速计算最小的愤怒值总和。以下是详细的解决方案和实现步骤:

问题分析

  1. 糖果的种类和数量

    • 每个糖果有一个类型,代表不同的种类。
    • 我们需要跟踪每种类型的糖果数量,以便在分配时计算重复的糖果数量,从而确定愤怒值。
  2. 操作类型

    • 添加糖果 (1 x):增加一种类型为 x 的糖果数量。
    • 删除糖果 (2 x):减少一种类型为 x 的糖果数量,保证删除前该类型至少有一个糖果。
    • 查询 (3 k):将所有糖果分给 k 个小朋友,计算最小的愤怒值总和。

解决思路

为了高效地处理大规模的数据,我们采用以下策略:

  1. 频率计数

    • 使用一个数组 f[x] 来记录每种类型 x 的糖果数量。
  2. 利用树状数组(Fenwick Tree)

    • 我们需要快速查询糖果数量大于 k 的类型数量以及这些类型的总糖果数。
    • 为此,我们使用两个树状数组:
      • BIT_freq:记录每个频率(糖果数量)对应的类型数量。
      • BIT_f_freq:记录每个频率对应的糖果总数。
  3. 处理操作

    • 添加糖果
      • 更新 f[x] 的值。
      • 更新 BIT_freqBIT_f_freq,减少旧频率的计数,增加新频率的计数。
    • 删除糖果
      • 同样更新 f[x] 的值。
      • 更新两个树状数组,减少旧频率的计数,增加新频率的计数(如果新频率大于零)。
    • 查询
      • 通过 BIT_freq 查询频率大于 k 的类型数量 cnt_over
      • 通过 BIT_f_freq 查询这些类型的糖果总数 sum_f_over
      • 计算总愤怒值为 sum_f_over - k * cnt_over
  4. 优化

    • 快速输入输出:使用 ios::sync_with_stdio(false)cin.tie(0) 来加速输入输出操作。
    • 预处理:初始化频率计数和树状数组。

C++ 实现

以下是基于上述思路的 C++ 实现:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;// 树状数组结构体
struct BIT {int size;vector<ll> tree;BIT(int n){size = n;tree.assign(n+2, 0LL);}// 更新操作:在 index 位置增加 deltavoid add(int index, ll delta){while(index <= size){tree[index] += delta;index += index & (-index);}}// 查询前缀和ll query(int index){ll res = 0;while(index > 0){res += tree[index];index -= index & (-index);}return res;}// 查询区间和 [l, r]ll query_range(int l, int r){if(l > r) return 0;return query(r) - query(l-1);}
};int main(){ios::sync_with_stdio(false);cin.tie(0);int n, q;cin >> n >> q;// 假设类型编号从 1 到 n// f[x] 表示类型 x 的糖果数量vector<int> f(n+1, 0);for(int i = 0; i < n; i++){int a;cin >> a;f[a]++;}// 最大可能的频率是 n + q,设为 2e6 以适应所有操作int MAX_F = 2000001;BIT BIT_freq(MAX_F);     // 记录每个频率对应的类型数量BIT BIT_f_freq(MAX_F);   // 记录每个频率对应的糖果总数// 初始化树状数组for(int x = 1; x <= n; x++){if(f[x] >= 1){BIT_freq.add(f[x], 1);BIT_f_freq.add(f[x], (ll)f[x]);}}// 处理每个操作while(q--){int op;cin >> op;if(op == 1){// 添加糖果int x;cin >> x;int old_f = f[x];int new_f = old_f + 1;if(old_f >= 1){BIT_freq.add(old_f, -1);BIT_f_freq.add(old_f, - (ll)old_f);}f[x] = new_f;BIT_freq.add(new_f, 1);BIT_f_freq.add(new_f, (ll)new_f);}else if(op == 2){// 删除糖果int x;cin >> x;int old_f = f[x];int new_f = old_f - 1;BIT_freq.add(old_f, -1);BIT_f_freq.add(old_f, - (ll)old_f);f[x] = new_f;if(new_f >= 1){BIT_freq.add(new_f, 1);BIT_f_freq.add(new_f, (ll)new_f);}}else if(op == 3){// 查询int k;cin >> k;if(k >= MAX_F){// 没有频率大于 k 的类型cout << "0\n";continue;}// 查询频率大于 k 的糖果总数ll sum_f_over = BIT_f_freq.query_range(k+1, MAX_F);// 查询频率大于 k 的类型数量ll cnt_over = BIT_freq.query_range(k+1, MAX_F);// 计算总愤怒值ll total_anger = sum_f_over - ((ll)k * cnt_over);cout << total_anger << "\n";}}
}

代码解释

  1. 树状数组(BIT)的实现

    • add(int index, ll delta):在指定位置 index 增加 delta
    • query(int index):查询从 1index 的前缀和。
    • query_range(int l, int r):查询区间 [l, r] 的和。
  2. 初始化

    • 读取初始糖果种类,更新频率数组 f
    • 根据初始频率,初始化两个树状数组 BIT_freqBIT_f_freq
  3. 处理每个操作

    • 添加糖果 (1 x)
      • 减少旧频率在 BIT_freqBIT_f_freq 中的计数。
      • 增加新频率在两个树状数组中的计数。
    • 删除糖果 (2 x)
      • 减少旧频率在两个树状数组中的计数。
      • 如果新的频率大于等于 1,则在两个树状数组中增加新频率的计数。
    • 查询 (3 k)
      • 使用 BIT_f_freq 查询频率大于 k 的糖果总数 sum_f_over
      • 使用 BIT_freq 查询频率大于 k 的类型数量 cnt_over
      • 计算总愤怒值 total_anger = sum_f_over - k * cnt_over
  4. 注意事项

    • 确保 k 不超过 MAX_F,否则愤怒值为 0
    • 使用 long long 类型防止溢出,因为糖果数量可能很大。

总结

通过使用树状数组,我们能够在对糖果种类进行动态更新的同时,快速响应查询操作。这种方法能够在 O(log N) 的时间复杂度内完成每次更新和查询,适用于大规模的数据处理需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/69395.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

【 java 安全】Java对象都是堆上分配?看完Java中对象逃逸分析就知道答案了

原创 龙虾编程随着JIT编译期的发展与逃逸分析技术逐渐成熟,所有的对象都分配到堆上也渐渐变得不是一定的。在编译期间JIT会对代码做很多优化,其中有一部分优化是减少内存堆分配压力,这里有一种重要的技术叫逃逸分析。逃逸分析是一种可以有效减少Java程序中同步负载和内存堆分…

【SQL SERVER】PIVOT与UNPIVOT之行列转换

基础例子 在数据处理的过程中,常常遇到行列转换的问题。例如,人员的考勤。可能表格中,1~12月都在同一个字段,实际中,为了查看方便,同一个人的考勤记录,能在同一行,这样查询起来比较方便(行转列)。或者,表格设计的时候就是1~12月,在其他数据分析时需要将列转行。即类…

SkyWalking组件自定义链路追踪

SkyWalking组件通过添加相关配置就可以获取到接口的相关信息,更加方便的追踪和处理问题 接下去讲下步骤: 1、在service层添加两个注解;@Trace@Tags({@Tag(key = "getDataByCode",value = "returnedObj"),@Tag(key = "getDataByCode",value = …

沈师傅食品携手纷享销客CRM系统,加速数字化转型

沈师傅食品有限公司是一家专业研发、生产和销售鸡蛋干系列产品的大型集团 公司,技术与研发实力雄厚,先后获得多项国家专利。公司成立于2006年,开创 了全新的鸡蛋干品类,创办人沈国平先生素有“鸡蛋干之父”之称,先后被央视、 四川电视台、北京卫视、优酷、凤凰网等国内知名…

总奖金高达10万元!华为算法精英实战营“亲和任务调度系统”来啦!

在无线领域,利用AI技术对任务准确建模、多核系统任务最优调度等问题都是非常有价值的算法难题。随着物联网、大数据、AI时代的到来,时延、可靠性等指标要求越来越高,海量的数据分析、大量复杂的运算对CPU的算力要求越来越高。CPU内部的大部分资源用于缓存和逻辑控制,适合运…

高产胜那啥,带你上线我的新项目!

希望大家能通过这个项目掌握企业级项目的开发、优化和上线方法,得到全方面编程技能和程序员素养的提升。大家好,我是程序员鱼皮。9月,我处于极度爆肝状态,成功完结了最新带大家做的项目 面试刷题平台 。当我们做完一个项目后,一定要记得把项目上线,这样才算是完成了学习的…

webapi 创建(空)

1. 打开vs2019 ,选择创建新项目2. 选择ASP.NET Web 应用程序(.NET Framework)3. 配置项目信息(名称,位置,框架)4. 选择空模板(WebAPI复选框选中)5. 这样里面就没有MVC的三层,因为前后端分离,webapi中只有两层。6. 空的WebApi程序创建完成。

.NET 代码混淆工具-JIEJIE.NETWX

阅读目录前言 项目介绍 项目功能 项目效果:蓝猫机场 项目地址 最后前言 JIEJIE.NET是一款强大的开源.NET程序集混淆工具。它利用深度加密技术和多样化的混淆策略,有效地保护了.NET软件的版权和源代码安全,防止未经授权的访问和篡改。 项目介绍 JIEJIE.NET是一个用C#开发的开源…