销售不跟踪,最终一场空!

【销售不跟踪,最终一场空!】美国专业营销人员协会报告显示:80%的销售是在第4至11次跟踪后完成! 如何做好跟踪与互动? 1,特殊的跟踪方式加深印象; 2,为互动找到漂亮借口; 3,注意两次跟踪间隔,建议2-3周; 4,每次跟踪切勿流露出急切愿望; 5,先卖自己,再卖观念!
内容概要:本文针对国内加密货币市场预测研究较少的现状,采用BP神经网络构建了CCi30指数预测模型。研究选取2018年3月1日至2019年3月26日共391天的数据作为样本,通过“试凑法”确定最优隐结点数目,建立三层BP神经网络模型对CCi30指数收盘价进行预测。论文详细介绍了数据预处理、模型构建、训练及评估过程,包括数据归一化、特征工程、模型架构设计(如输入层、隐藏层、输出层)、模型编译与训练、模型评估(如RMSE、MAE计算)以及结果可视化。研究表明,该模型在短期内能较准确地预测指数变化趋势。此外,文章还讨论了隐层节点数的优化方法及其对预测性能的影响,并提出了若干改进建议,如引入更多技术指标、优化模型架构、尝试其他时序模型等。 适合人群:对加密货币市场预测感兴趣的研究人员、投资者及具备一定编程基础的数据分析师。 使用场景及目标:①为加密货币市场投资者提供一种新的预测工具和方法;②帮助研究人员理解BP神经网络在时间序列预测中的应用;③为后续研究提供改进方向,如数据增强、模型优化、特征工程等。 其他说明:尽管该模型在短期内表现出良好的预测性能,但仍存在一定局限性,如样本量较小、未考虑外部因素影响等。因此,在实际应用中需谨慎对待模型预测结果,并结合其他分析工具共同决策。
# P13239 「2.48sOI R1」化妆品 ## 题目背景 本月 $30$ 日即将迎来埃尔萨纳城的第 $17367$ 次名媛聚会。Misserina 和 ShenTianYi_ 正在为此做准备,她们在商场购买化妆品。 ## 题目描述 商场里面有 $2n$ 个化妆品,每一个都能提供时尚值和美丽值。任意两个化妆品提供的时尚值互相同,且美丽值也互相同。 Misserina 和 ShenTianYi_ 要选择 $n$ 次心仪的化妆品,每一次 Misserina 先选,ShenTianYi_ 后选。Misserina 是个性格多变的人,她时而希望自己更加时尚,时而希望自己更加美丽,会选择剩余的化妆品中该值最大的那一个;而 ShenTianYi_ 则是淑女中的淑女,每一次 Misserina 选择她想要的之后她都会选择 Misserina 最想要的那个,也就是对应时尚值或美丽值最小的那个。 她们想知道,按照这个规则选完所有化妆品之后,两人的时尚值和美丽值分别为多少。请帮她们解答这个问题。 ## 输入格式 第一行:一个整数 $n$,含义如题干所示。 第二行:$2n$ 个整数 $F_1,F_2,\dots,F_{2n}$,表示每一个化妆品提供的时尚值。 第三行:$2n$ 个整数 $B_1,B_2,\dots,B_{2n}$,表示每一个化妆品提供的美丽值。 第四行:$n$ 个整数 $Q_1,Q_2,\dots,Q_n$,表示 Misserina 每次希望购买时尚值最高的(用 `1` 表示)还是美丽值最高的(用 `2` 表示)。 ## 输出格式 第一行两个整数,分别表示最终 Misserina 的时尚值和美丽值。 第二行两个整数,分别表示最终 ShenTianYi_ 的时尚值和美丽值。 ## 输入输出样例 #1 ### 输入 #1 ``` 3 1 7 3 8 9 4 1665 5 8888 3 4 27 1 1 2 ``` ### 输出 #1 ``` 21 34 11 10558 ``` ## 说明/提示 第一次选择: Misserina 选择时尚值最高的即第 $5$ 种化妆品,ShenTianYi_ 选择时尚值最低的即第 $1$ 种化妆品。 第二次选择: Misserina 选择剩下的时尚值最高的即第 $4$ 种化妆品,ShenTianYi_ 选择剩下的时尚值最低的第 $3$ 种化妆品。 第三次选择: Misserina 选择剩下的美丽值最高的第 $6$ 种化妆品,ShenTianYi_ 选择剩下的美丽值最低的第 $2$ 种化妆品。 最终 Misserina 的时尚值为 $8+9+4=21$,美丽值为 $3+4+27=34$;ShenTianYi_ 的时尚值为 $1+7+3=11$,美丽值为 $1665+5+8888=10558$。 对于 $100\%$ 数据: - $1 \le n \le 5 \times 10^5$; - $1 \le F_i,B_i \le 10^9$; - $Q_i \in \{1,2\}$; - $\forall\: i \ne j$,$F_i \ne F_j$,$B_i \ne B_j$。 **本题采取捆绑测试。** - Subtask 0(9 pts):$1 \le n \le 1000$,$1 \le F_i,B_i \le 2000$,$Q_i$ 均为 `1` 或均为 `2`; - Subtask 1(11 pts):$1 \le n \le 1000$,$1 \le F_i,B_i \le 2000$; - Subtask 2(20 pts):$1 \le n \le 1000$,$1 \le F_i,B_i \le 10^9$; - Subtask 3(26 pts):$1 \le n \le 5 \times 10^5$,$1 \le F_i,B_i \le 10^9$,$Q_i$ 均为 `1` 或均为 `2`; - Subtask 4(34 pts):$1 \le n \le 5 \times 10^5$,$1 \le F_i,B_i \le 10^9$。 ## 思路: >1.把$$a,b$$两个数组从小到大排序($$a$$数组是指 _时尚_ 值,$$b$$数组是指 _美丽_ 值)。 >2.模拟每次两个人取出的过程,比如:Misserina 先取出$$a[n]$$,而ShenTianYi_ 就取出$$a[1]$$。是是很简单? 但是,在数组中删除元素容易,一位一位挪肯定会~~喜提~~超时,所以我们掏出vector。 使用vector需要```#include <vector>```头文件,推荐一篇别人的博客(侵权请联系删除):[点我这里~](https://blog.youkuaiyun.com/m0_56494923/article/details/123263285?ops_request_misc=%257B%2522request%255Fid%2522%253A%25221da9913098733efca2fe4584e444afdc%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=1da9913098733efca2fe4584e444afdc&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-123263285-null-null.142^v102^pc_search_result_base7&utm_term=vector&spm=1018.2226.3001.4187) 所以,核心部分大致总结为: >如果要取的是时尚的,就取出后去除$$a[n]$$和$$a[1]$$; >如果要取的是美丽的,就取出后去除$$b[n]$$和$$b[1]$$。 > 最后,警示大家: **十场OI一场空开long long见祖宗。** 请按题解方式用c++写出这题
07-13
<think>题目要求:模拟两人轮流选择化妆品的过程,每次Misserina根据当前指令选择剩余化妆品中时尚值或美丽值最大的那个,ShenTianYi_则选择对应属性(与Misserina选择的属性相同)的最小值。 注意:每次选择后,两个化妆品会被移除(一个被Misserina选走,一个被ShenTianYi_选走)。但是,每个化妆品有两个属性,所以当我们按照一个属性排序并移除时,另一个属性也要相应移除。 然而,直接模拟删除操作(比如使用vector的erase)会导致每次删除的复杂度为O(n),总复杂度为O(n^2),对于n=500000(总共有1000000个元素)显然会超时。 因此,我们需要更高效的方法。 思路: 我们可以预先将化妆品按照时尚值和美丽值分别排序,并记录每个化妆品在另一个数组中的位置(或者使用索引)。但是,由于每次选择后,化妆品会被移除,我们需要维护两个数组(时尚值和美丽值)中哪些元素已经被移除。 另一种思路是使用“双指针”和“懒惰删除”策略(即使用堆或平衡树,但C++标准库中没有内置平衡树,我们可以用set,但set的删除也是O(log n)的,总复杂度O(n log n)可以接受,但常数较大,且需要处理两个属性)。 然而,题目要求n最大50万,总共有100万个元素,使用set的复杂度为O(n log n)是可行的。 具体做法: 1. 我们建立两个multiset(或者set,因为题目说所有值互相同,所以用set即可)来分别维护时尚值和美丽值,并且每个化妆品用一个结构体表示,包含时尚值、美丽值和唯一标识(比如索引)。 2. 同时,我们还需要建立两个数组,分别按时尚值和美丽值排序,但为了方便快速删除,我们使用两个set,分别按照时尚值和美丽值作为关键字排序。 但是,当我们删除一个化妆品时,需要同时在两个set中删除,这要求我们能够通过一个化妆品对象在两个set中找到并删除。我们可以使用指针或者索引,但是set支持随机访问。另一种方法是使用两个set,每个set存储化妆品对象的指针,但这样删除时需要在另一个set中查找相同的对象,效率高。 改进:使用一个set,但是按照两种排序方式分别建立两个set,并存储相同的元素(对象)。这样,当删除时,我们需要在两个set中都删除,但如何关联?我们可以用两个set,每个set存储相同的化妆品对象的指针,然后删除时,通过指针在两个set中删除。但是,这样需要两次删除操作,每次O(log n),总删除操作O(n log n)。 然而,题目要求模拟n轮,每轮操作包括: - 根据Q_i,在剩余化妆品中,选择时尚值最大(或美丽值最大)的化妆品(Misserina选)。 - 然后,在剩余化妆品中,选择同属性(即如果Misserina按时尚选,则ShenTianYi_按时尚选最小;如果按美丽选,则按美丽选最小)的最小值(ShenTianYi_选)。 所以,我们可以维护两个set: set_f: 按时尚值排序,存储所有化妆品。 set_b: 按美丽值排序,存储所有化妆品。 但是,当我们删除一个化妆品时,需要在两个set中同时删除。 具体步骤: 1. 初始化:将2n个化妆品加入两个set中。每个化妆品可以用一个结构体表示,包含f(时尚值)、b(美丽值)和id(可选,用于调试,但非必须)。 2. 对于每一轮选择(n轮): 读取Q_i: 如果Q_i==1(按时尚选): 则从set_f中取出最大的元素(即最后一个元素,或者用rbegin()获取)作为Misserina的选择,记为A。 然后,从set_f中取出最小的元素(即第一个元素,begin())作为ShenTianYi_的选择,记为B。 注意:这里ShenTianYi_选的是时尚值最小的,但题目要求是“对应属性”的最小值,即也是时尚属性。 如果Q_i==2(按美丽选): 则从set_b中取出最大的元素作为Misserina的选择,记为A。 然后,从set_b中取出最小的元素作为ShenTianYi_的选择,记为B。 但是,这里有一个问题:当我们从set_f中删除A和B时,也要在set_b中删除A和B。同样,从set_b中删除时,也要在set_f中删除。 因此,每轮操作: - 根据Q_i选择主set(如果是1,则主set为set_f;如果是2,则主set为set_b)。 - 从主set中取最大元素(Misserina选)和最小元素(ShenTianYi_选)。 - 将这两个元素从两个set中删除。 注意:有可能在取最小元素时,这个元素已经被删除?会,因为我们是同时从两个set中删除,但这里我们是一次性取两个元素,然后同时删除两个元素(两个化妆品)。 但是,有一个重要问题:当Q_i==1时,我们从set_f中取最大和最小,然后删除这两个化妆品。那么,在set_b中,我们也要删除这两个化妆品。同样,当Q_i==2时,从set_b中取最大和最小,然后删除,同时也要在set_f中删除这两个。 然而,当我们从set_f中取最小元素时,这个元素在set_b中可能是最小的?但是,题目要求:ShenTianYi_选择的是在剩余化妆品中,与Misserina选择的属性相同的最小值。所以,当Misserina按时尚选时,ShenTianYi_就选剩余中时尚值最小的;当按美丽选时,就选剩余中美丽值最小的。 所以,我们的做法正确。 3. 统计:分别累计Misserina和ShenTianYi_的时尚值和美丽值。 注意:因为每个化妆品有两个属性,所以当我们删除一个化妆品时,它的两个属性都要被计入对应的人。 如何记录?每轮中,Misserina选的化妆品(记为A)的两个属性(fA, bA)都加到Misserina的时尚值和美丽值上;同样,ShenTianYi_选的化妆品(记为B)的两个属性(fB, bB)加到ShenTianYi_的时尚值和美丽值上。 4. 实现细节:我们使用两个set,每个set存储化妆品,但按照同的属性排序。我们可以定义两个比较结构体。 结构体定义: struct Item { long long f, b; // 为了区分,我们也可以存id,但非必须,因为两个属性都是唯一的,所以可以用属性值来区分?但是有可能两个同的化妆品具有相同的属性值?题目说任意两个化妆品的时尚值互相同,美丽值互相同。所以我们可以用f或b作为唯一标识?但是一个化妆品同时有f和b,所以我们需要同时存储f和b。 // 注意:同一个化妆品在两个set中存储的是相同的f和b,所以我们可以用f和b来比较,但是删除时需要找到对应的元素。 }; 但是,set中存储的是元素的副本,所以当我们删除时,需要删除两个set中相同的元素(即相同的化妆品)。我们可以用指针,但这样管理内存复杂。或者,我们可以用数组存储所有化妆品,然后set中存储索引。这样,删除时通过索引找到化妆品,然后删除两个set中的索引。 另一种方法:使用两个set,分别存储指针,但是这样需要自己管理内存,而且容易出错。 更简单的方法:使用两个set,每个set存储pair<属性值, 唯一标识>,其中唯一标识可以是该化妆品的索引(0~2n-1)。这样,当我们从主set中选出一个元素(通过属性值和索引)后,我们可以通过索引去另一个set中删除对应的元素(另一个set中存储的是<另一个属性, 同一索引>)。 具体: set_f: set<pair<long long, int>> 按f排序(默认按pair的first排序,即按f升序),但我们取最大元素时,用rbegin()。 set_b: set<pair<long long, int>> 按b排序。 同时,我们还需要两个数组:F[2n]和B[2n],存储每个索引对应的f和b值。 操作步骤: 初始化: 输入n,然后输入2n个F[i]和2n个B[i](i从0到2n-1)。 初始化两个set: set_f: 对于i=0~2n-1,插入{F[i], i} set_b: 插入{B[i], i} 然后,我们还需要一个数组deleted[2n](或者用两个set来维护已经被删除的索引?)来标记哪些化妆品已经被删除?但这样我们每次删除时,需要删除两个set中的对应元素,所以能仅仅标记,而是要从set中删除。 对于每一轮: 读入Q(1或2) 如果Q==1: 从set_f中取最后一个元素(最大的f)-> 即rbegin(),得到(f_max, idx1) -> 这是Misserina选的。 从set_f中取第一个元素(最小的f)-> begin(),得到(f_min, idx2) -> 这是ShenTianYi_选的。 然后,将这两个元素从set_f和set_b中删除。注意:删除时,我们根据索引idx1和idx2,在set_b中找到对应的元素(即{B[idx1], idx1}和{B[idx2], idx2})并删除。同样,在set_f中也要删除这两个元素(实际上,我们在set_f中已经知道了这两个元素,但是set_f中我们是通过f值来存储的,所以我们可以直接删除我们取出的这两个元素(通过迭代器或者值)?但是,set_f中我们取第一个元素(begin())的迭代器是begin(),取最后一个元素(rbegin())的迭代器是--end()?注意:rbegin()返回的是反向迭代器,删除时需要转换为正向迭代器。 具体删除: 对于Misserina选的元素(f_max, idx1): 在set_f中,我们可以用迭代器(对于最后一个元素,我们可以用--set_f.end())来删除,但是注意:我们取的时候已经知道它是最后一个,所以我们可以保存这个迭代器。但是,我们取的时候用的是rbegin(),它返回的是反向迭代器,我们可以用base()转换,但容易出错。 另一种方法:我们用反向迭代器,而是用set的end()迭代器递减来获取最后一个元素。因为set的迭代器是双向迭代器。 步骤: auto it1 = set_f.end(); it1--; // 指向最后一个元素 auto miss = *it1; // 得到最后一个元素 auto it2 = set_f.begin(); auto shen = *it2; 然后,删除这两个元素:set_f.erase(it1); set_f.erase(it2); 同时,在set_b中,我们需要通过索引miss.idx和shen.idx来删除。所以,我们需要在set_b中删除包含索引miss.idx和shen.idx的元素。但是,set_b是按b值排序的,我们知道b值,但是我们知道索引。所以,我们需要一个辅助数据结构:记录每个索引在set_b中的位置?或者,我们可以在set_b中搜索pair<B[idx], idx>,因为B[idx]我们知道(通过数组B),所以我们可以用这个pair来删除。 但是,注意:set的删除可以传入值,只要这个值等于set中的某个元素(pair的比较是先比较第一个元素,再比较第二个元素)。所以,我们可以: set_b.erase({B[miss.idx], miss.idx}); set_b.erase({B[shen.idx], shen.idx}); 但是,这样删除的复杂度是O(log n),所以总删除操作是O(log n)。 注意:同样,当Q==2时,我们从set_b中取最大和最小,然后删除,并在set_f中删除对应的元素。 然后,将Misserina选的化妆品的两个属性(f_max, B[miss.idx])加到Misserina的总时尚和总美丽上;将ShenTianYi_选的(f_min, B[shen.idx])加到ShenTianYi_的总时尚和总美丽上。 但是,注意:在Q==1时,Misserina选的是时尚值最大的,所以她的时尚值加上f_max,美丽值加上B[miss.idx];ShenTianYi_选的是时尚值最小的,所以她的时尚值加上f_min,美丽值加上B[shen.idx]。 同样,当Q==2时: 从set_b中取最大(最后一个)和最小(第一个)元素。 miss = 最大元素(b_max, idx1),shen = 最小元素(b_min, idx2) 然后,在set_f和set_b中删除这两个元素(通过索引)。 Misserina的时尚值加上F[idx1](因为时尚值存储在F数组中),美丽值加上b_max;ShenTianYi_的时尚值加上F[idx2],美丽值加上b_min。 注意:删除元素后,这两个化妆品就被移除了,下一轮就会再出现。 但是,有一个问题:当删除元素时,我们可能会删除同一个元素吗?即Misserina选的和ShenTianYi_选的是同一个?可能,因为时尚值(或美丽值)互相同,最大值和最小值一定同(除非只有一个元素,但每轮开始至少有两个元素)。 另外,每轮删除两个元素,总共n轮,删除2n个元素。 复杂度:每轮操作是O(log n)(因为set的删除和取最大最小都是O(log n)),总复杂度O(n log n),对于n=500000,大约500000*log2(500000)≈500000*19=9.5e6,可以接受。 但是,我们需要注意,在删除时,我们通过索引去另一个set中删除,需要构造一个pair(属性值,索引),而属性值我们通过数组B(或F)得到。所以,我们需要两个数组F和B,大小为2n,存储每个索引对应的时尚值和美丽值。 步骤总结: 1. 输入n,然后输入2n个F[i]和2n个B[i](i从0到2n-1)。 2. 初始化两个set: set_f: set<pair<long long, int>>,按f升序(默认) set_b: set<pair<long long, int>>,按b升序 将每个索引i插入两个set:set_f.insert({F[i], i}); set_b.insert({B[i], i}); 3. 初始化四个累加变量:long long m_f=0, m_b=0, s_f=0, s_b=0; (分别表示Misserina的时尚值和美丽值,ShenTianYi_的时尚值和美丽值) 4. 循环n次,每次读入一个Q: if (Q == 1) { // 从set_f中取最大(最后一个)和最小(第一个) auto it_miss = set_f.end(); it_miss--; // 指向最后一个元素 auto it_shen = set_f.begin(); // 获取值 int idx_miss = it_miss->second; int idx_shen = it_shen->second; // 加到Misserina m_f += F[idx_miss]; m_b += B[idx_miss]; // 加到ShenTianYi_ s_f += F[idx_shen]; s_b += B[idx_shen]; // 从set_f中删除这两个元素(通过迭代器) set_f.erase(it_miss); set_f.erase(it_shen); // 从set_b中删除这两个元素(通过值:需要构造pair,注意pair的first是B[idx]) set_b.erase({B[idx_miss], idx_miss}); set_b.erase({B[idx_shen], idx_shen}); } else { // Q==2 // 从set_b中取最大(最后一个)和最小(第一个) auto it_miss = set_b.end(); it_miss--; auto it_shen = set_b.begin(); int idx_miss = it_miss->second; int idx_shen = it_shen->second; m_f += F[idx_miss]; m_b += B[idx_miss]; s_f += F[idx_shen]; s_b += B[idx_shen]; set_b.erase(it_miss); set_b.erase(it_shen); // 同时从set_f中删除 set_f.erase({F[idx_miss], idx_miss}); set_f.erase({F[idx_shen], idx_shen}); } 5. 输出: cout << m_f << " " << m_b << endl; cout << s_f << " " << s_b << endl; 但是,这里有一个问题:在Q==1时,我们从set_f中删除两个元素,然后从set_b中删除两个元素。但是,在删除set_b中的元素时,我们使用了{B[idx], idx},这个pair在set_b中是存在的,因为一开始就插入了。同样,在Q==2时,我们也是类似操作。 但是,注意:在删除set_b中的元素时,我们使用的是set_b.erase(pair),这个操作会删除与pair相等的元素。因为set中每个元素是唯一的(索引唯一),所以可以正确删除。 但是,有一个潜在的坑:在Q==1时,我们删除的两个元素,有可能在set_b中已经被删除了吗?会,因为我们是第一次删除这两个元素。 但是,注意:在Q==1时,我们删除的两个元素(idx_miss和idx_shen)可能是同一个化妆品吗?可能,因为最大值和最小值在剩余化妆品中肯定同(且剩余化妆品至少有两个)。 然而,还有一种情况:当我们在set_f中删除两个元素时,这两个元素在set_b中对应的元素可能会影响set_b的迭代器吗?会,因为set_b和set_f是独立的。 但是,在删除时,我们需要注意:在Q==1中,我们先从set_f中删除了两个元素,然后从set_b中删除。同样,在Q==2中,我们先从set_b中删除两个元素,然后从set_f中删除。这样没有问题。 但是,在Q==1中,我们通过迭代器删除了set_f中的两个元素,然后通过值删除set_b中的两个元素。同样在Q==2中,我们通过迭代器删除了set_b中的两个元素,然后通过值删除set_f中的两个元素。 注意:在删除set_f中的元素时,我们使用的是迭代器,而在删除另一个set中的元素时,我们使用的是值(构造pair)。这样是安全的。 但是,在Q==1中,当我们删除set_f中的元素后,set_f的迭代器会失效吗?会,因为我们删除了两个迭代器指向的元素,但是我们已经保存了它们的索引,所以后续操作依赖于这两个迭代器。 然而,在删除set_b中的元素时,我们使用的是值,所以会受到set_f删除的影响。 但是,有一个问题:在Q==1中,我们通过set_f的迭代器删除了元素,然后我们通过索引去set_b中删除。但是,在set_f中删除元素后,这两个元素在set_b中仍然存在,所以我们可以正常删除。 因此,代码可以这样写。 但是,我们需要注意:在删除时,如果set中存在这个元素,erase会怎样?因为我们的操作是成对的,所以会出现存在的情况。 然而,有一个边界情况:在删除set_b中的元素时,我们构造的pair必须和插入时完全一致(包括索引和属性值)。由于属性值在数组中存储,而数组没有被修改,所以属性值正确。索引也正确。 但是,注意:在Q==1中,我们删除的两个元素(idx_miss和idx_shen)可能是同一个吗?可能,因为最大值和最小值同(除非只有一个元素,但每轮开始时至少有两个元素)。 所以,我们按照上述步骤编写代码。 但是,注意:在set中,我们存储的是pair,而pair的默认比较是先比较第一个元素(属性值),如果第一个元素相等,再比较第二个元素(索引)。由于属性值互相同,所以即使两个同的化妆品有相同的属性值(但题目中属性值互相同,所以会相同),所以会冲突。而且,索引也是唯一的。 因此,代码实现如下: 注意:使用set的end()和begin()迭代器,以及删除操作。 但是,在删除迭代器时,要注意:删除后迭代器失效,所以我们在删除之前需要保存需要的信息(比如索引)。 另外,在删除set_b中的元素时,我们使用erase({B[idx], idx}),这需要O(log n)时间,但总复杂度O(n log n)可以接受。 我们写代码时,注意使用long long。 但是,有一个问题:在Q==1时,我们取set_f的最大和最小,但是注意,set_f中存储的是按f升序排列的,所以begin()是最小,end()-1是最大。 同样,set_b中存储的是按b升序排列。 所以,上述方法正确。 但是,在Q==1时,我们删除的两个化妆品,在set_b中删除时,我们使用的是B[idx](即该化妆品在数组B中的值),这个值在删除前没有改变,所以正确。 最后,输出即可。 但是,我们需要注意:在删除过程中,我们可能会删除一个在另一个set中已经被删除的元素吗?会,因为每轮我们删除两个同的化妆品,并且这两个化妆品在之前没有被删除。 因此,代码实现如下: 注意:由于n最大50万,总共有100万个元素,所以我们需要使用set,并注意常数。set的erase和insert都是O(log n),所以总操作次数为4*n=200万次,每次O(log n),总时间大约2000000 * log2(1000000) ≈ 2000000 * 20 = 40000000,即4e7,在C++中应该可以接受。 但是,为了保险,我们可以使用更快的输入输出(如scanf/printf)。 我们使用C++标准输入输出,并关闭同步,或者使用scanf/printf。 由于题目中数据范围较大(10^9),所以使用long long。 代码: 注意:在set中,我们存储的pair是<属性值, 索引>,索引从0开始。 输入输出样例的验证: 输入:n=3, F=[1,7,3,8,9,4], B=[1665,5,8888,3,4,27], Q=[1,1,2] 初始化: set_f: 按f升序:{1,0}, {3,2}, {4,5}, {7,1}, {8,3}, {9,4} -> 注意:输入是6个数,索引0~5 set_b: 按b升序:{3,3}, {4,4}, {5,1}, {27,5}, {1665,0}, {8888,2} 第一轮:Q=1 从set_f取最大:{9,4} -> Misserina选:时尚值9,美丽值B[4]=4(因为索引4在B数组中是4) 从set_f取最小:{1,0} -> ShenTianYi_选:时尚值1,美丽值B[0]=1665 然后,从set_f中删除这两个元素:删除{1,0}和{9,4},set_f变为:{3,2},{4,5},{7,1},{8,3} 从set_b中删除这两个元素:删除{B[0]=1665,0}即{1665,0}和{B[4]=4,4}即{4,4},set_b变为:{3,3},{5,1},{27,5},{8888,2} 此时,Misserina的时尚值=9,美丽值=4;ShenTianYi_的时尚值=1,美丽值=1665。 第二轮:Q=1 从set_f取最大:{8,3} -> Misserina选:时尚值8,美丽值B[3]=3 从set_f取最小:{3,2} -> ShenTianYi_选:时尚值3,美丽值B[2]=8888 删除:set_f中删除{3,2}和{8,3},set_f变为:{4,5},{7,1} set_b中删除{B[3]=3,3}即{3,3}和{B[2]=8888,2}即{8888,2},set_b变为:{5,1},{27,5} 此时,Misserina累计:时尚值9+8=17,美丽值4+3=7;ShenTianYi_累计:1+3=4,美丽值1665+8888=10553。 第三轮:Q=2 从set_b中取最大:{27,5} -> Misserina选:美丽值27,时尚值F[5]=4 从set_b中取最小:{5,1} -> ShenTianYi_选:美丽值5,时尚值F[1]=7 删除:set_b中删除{5,1}和{27,5},set_b为空。 set_f中删除{F[5]=4,5}即{4,5}和{F[1]=7,1}即{7,1},set_f为空。 Misserina累计:时尚值17+4=21,美丽值7+27=34;ShenTianYi_累计:时尚值4+7=11,美丽值10553+5=10558。 输出: 第一行:21 34 第二行:11 10558 但是,样例输出第二行是11 10558,而我们的计算中ShenTianYi_的美丽值10558,但样例输出是10558?而样例输出是10558,但是我们的计算过程:第一轮1665,第二轮8888,第三轮5,总和=1665+8888+5=10558,正确。 但是,注意:样例输出第二行是“11 10558”,而我们计算ShenTianYi_的时尚值:1+3+7=11,美丽值:1665+8888+5=10558。 所以,输出正确。 因此,我们按照这个思路编写代码。 但是,注意:在删除时,我们使用set_b.erase({B[idx], idx}),这里B[idx]是数组中的值,而idx是索引,所以正确。 代码实现: 注意:使用set时,迭代器删除后,该迭代器失效,所以我们在删除前已经保存了索引,所以没有问题。 另外,在循环中,我们每次删除两个元素,共n轮,删除2n个元素。 但是,在Q==1时,我们删除了set_f中的两个元素,然后删除了set_b中的两个元素。在Q==2时,我们删除了set_b中的两个元素,然后删除了set_f中的两个元素。 所以,我们需要两个set:set_f和set_b。 代码: #include <iostream> #include <set> #include <vector> #include <cstdio> using namespace std; typedef long long LL; typedef pair<LL, int> PLI; // 存储(属性值,索引) int main() { int n; scanf("%d", &n); int m = 2 * n; vector<LL> F(m), B(m); for (int i = 0; i < m; i++) { scanf("%lld", &F[i]); } for (int i = 0; i < m; i++) { scanf("%lld", &B[i]); } vector<int> Q(n); for (int i = 0; i < n; i++) { scanf("%d", &Q[i]); } set<PLI> set_f, set_b; for (int i = 0; i < m; i++) { set_f.insert({F[i], i}); set_b.insert({B[i], i}); } LL m_f = 0, m_b = 0; // Misserina的时尚值和美丽值 LL s_f = 0, s_b = 0; // ShenTianYi_的时尚值和美丽值 for (int i = 0; i < n; i++) { if (Q[i] == 1) { // 从set_f中取最大(最后一个)和最小(第一个) auto it_miss = set_f.end(); it_miss--; // 指向最后一个元素 auto it_shen = set_f.begin(); int idx_miss = it_miss->second; int idx_shen = it_shen->second; // Misserina选的是最大的时尚值,所以加上这个化妆品的时尚值和美丽值 m_f += F[idx_miss]; m_b += B[idx_miss]; // ShenTianYi_选的是最小的时尚值,加上这个化妆品的时尚值和美丽值 s_f += F[idx_shen]; s_b += B[idx_shen]; // 从set_f中删除这两个元素(通过迭代器) set_f.erase(it_miss); set_f.erase(it_shen); // 从set_b中删除这两个元素(通过值) set_b.erase({B[idx_miss], idx_miss}); set_b.erase({B[idx_shen], idx_shen}); } else { // Q[i]==2 // 从set_b中取最大(最后一个)和最小(第一个) auto it_miss = set_b.end(); it_miss--; auto it_shen = set_b.begin(); int idx_miss = it_miss->second; int idx_shen = it_shen->second; m_f += F[idx_miss]; m_b += B[idx_miss]; s_f += F[idx_shen]; s_b += B[idx_shen]; // 从set_b中删除 set_b.erase(it_miss); set_b.erase(it_shen); // 从set_f中删除 set_f.erase({F[idx_miss], idx_miss}); set_f.erase({F[idx_shen], idx_shen}); } } printf("%lld %lld\n", m_f, m_b); printf("%lld %lld\n", s_f, s_b); return 0; } 但是,我们需要注意:在删除时,我们可能遇到这样的情况:在Q==1中,我们删除set_f中的两个元素后,再删除set_b中的两个元素。但是,有可能在删除set_b中的元素时,其中一个元素已经被删除了?会,因为每轮我们删除两个同的元素,而且这两个元素在之前没有被删除过。 所以,我们提交代码。 但是,注意:在删除set_b中的元素时,我们构造的pair必须和插入时完全一致。由于在数组中,B[idx]的值在删除过程中会改变,所以正确。 但是,有一个潜在的问题:在Q==1时,我们删除set_f中的两个元素后,这两个元素在set_b中仍然存在,所以可以删除。同样,在Q==2时,我们先删除了set_b中的两个元素,然后删除set_f中的两个元素,这两个元素在set_f中仍然存在。 所以,没有问题。 但是,我们考虑一个极端情况:在Q==1中,我们删除的两个元素,在set_b中删除时,其中一个元素可能已经被删除了吗?会,因为我们是第一次删除这两个元素。 因此,我们按照上述代码编写。 但是,在测试样例中,我们得到了正确结果,所以我们可以提交。 注意:在C++中,set的end()迭代器指向的是最后一个元素的下一个位置,所以递减一次就得到最后一个元素。 另外,在删除set_b中的元素时,我们使用{ B[idx], idx },由于B[idx]是数组中的值,而数组在初始化后没有改变,所以正确。 但是,我们需要注意:在删除set_b中的元素时,如果set_b中存在这个元素,erase会报错,但是会返回0(表示删除的元素个数),但这里我们确保存在,所以会出错。 因此,我们运行代码并测试样例。 样例输入: 3 1 7 3 8 9 4 1665 5 8888 3 4 27 1 1 2 输出: 21 34 11 10558 但是,我们计算一下: Misserina: 时尚值:9(第一轮)+8(第二轮)+4(第三轮)=21 美丽值:4(第一轮)+3(第二轮)+27(第三轮)=34 ShenTianYi_: 时尚值:1+3+7=11 美丽值:1665+8888+5=10558 所以输出正确。 但是,注意:第三轮Misserina选的是美丽值最大的,即27(索引5,时尚值为4),ShenTianYi_选的是美丽值最小的,即5(索引1,时尚值为7)。 因此,我们按照这个代码提交。 但是,由于n最大50万,我们需要注意常数。使用set,每个操作O(log n),总操作次数4*n=200万次,所以总时间大约是2000000 * log2(1000000) ≈ 2000000 * 20 = 40000000,即4e7,在C++中应该可以在2秒内完成(题目2.48秒)。 但是,我们使用scanf/printf来避免输入输出瓶颈。 最后,注意:在删除时,我们使用set_f.erase(iterator)和set_f.erase(iterator)两次,而set_b.erase(value)两次,每次erase是O(log n),所以总复杂度O(n log n)。 提交代码。 但是,我们可能遇到一个问题:在Q==1时,我们删除了set_f中的两个元素,然后删除set_b中的两个元素。但是,在删除set_b中的元素时,我们传入的pair是{B[idx], idx},而set_b中存储的pair的first是B[idx],所以可以匹配。但是,如果两个同的化妆品具有相同的B值?题目说美丽值互相同,所以会相同。同样,时尚值也互相同。 所以,没有问题。 因此,我们编写完整代码。</think>为了解决这个问题,我们需要模拟Misserina和ShenTianYi_两人轮流选择化妆品的过程。每次Misserina根据给定的指令选择剩余化妆品中时尚值或美丽值最大的那个,而ShenTianYi_则选择同属性值最小的那个。我们需要高效地处理每轮选择,并统计两人最终获得的时尚值和美丽值总和。 ### 方法思路 1. **数据结构选择**:使用两个`set`(集合)分别按时尚值和美丽值存储化妆品。每个化妆品表示为`pair<属性值, 索引>`,以便快速访问和删除。 2. **选择过程**: - **当指令为1(时尚值优先)**:从时尚值集合中取出最大值(Misserina选择)和最小值(ShenTianYi_选择),然后从两个集合中删除这两个化妆品。 - **当指令为2(美丽值优先)**:从美丽值集合中取出最大值(Misserina选择)和最小值(ShenTianYi_选择),然后从两个集合中删除这两个化妆品。 3. **统计结果**:在每轮选择中,将选中的化妆品属性值分别累加到两人的时尚值和美丽值总和中。 ### 解决代码 ```cpp #include <iostream> #include <set> #include <vector> #include <cstdio> using namespace std; typedef long long LL; typedef pair<LL, int> PLI; int main() { int n; scanf("%d", &n); int m = 2 * n; vector<LL> F(m), B(m); for (int i = 0; i < m; i++) { scanf("%lld", &F[i]); } for (int i = 0; i < m; i++) { scanf("%lld", &B[i]); } vector<int> Q(n); for (int i = 0; i < n; i++) { scanf("%d", &Q[i]); } set<PLI> set_f, set_b; for (int i = 0; i < m; i++) { set_f.insert({F[i], i}); set_b.insert({B[i], i}); } LL m_f = 0, m_b = 0; LL s_f = 0, s_b = 0; for (int i = 0; i < n; i++) { if (Q[i] == 1) { auto it_miss = set_f.end(); it_miss--; auto it_shen = set_f.begin(); int idx_miss = it_miss->second; int idx_shen = it_shen->second; m_f += F[idx_miss]; m_b += B[idx_miss]; s_f += F[idx_shen]; s_b += B[idx_shen]; set_f.erase(it_miss); set_f.erase(it_shen); set_b.erase({B[idx_miss], idx_miss}); set_b.erase({B[idx_shen], idx_shen}); } else { auto it_miss = set_b.end(); it_miss--; auto it_shen = set_b.begin(); int idx_miss = it_miss->second; int idx_shen = it_shen->second; m_f += F[idx_miss]; m_b += B[idx_miss]; s_f += F[idx_shen]; s_b += B[idx_shen]; set_b.erase(it_miss); set_b.erase(it_shen); set_f.erase({F[idx_miss], idx_miss}); set_f.erase({F[idx_shen], idx_shen}); } } printf("%lld %lld\n", m_f, m_b); printf("%lld %lld\n", s_f, s_b); return 0; } ``` ### 代码解释 1. **输入处理**:读取化妆品数量`n`,以及每个化妆品的时尚值`F`和美丽值`B`,还有每轮的选择指令`Q`。 2. **集合初始化**:创建两个集合`set_f`和`set_b`,分别按时尚值和美丽值升序存储化妆品(使用`pair<属性值, 索引>`)。 3. **选择过程**: - **指令1**:从`set_f`中取最大(最后一个元素)和最小(第一个元素)的时尚值化妆品,分别累加到Misserina和ShenTianYi_的总和,然后从两个集合中删除这两个化妆品。 - **指令2**:从`set_b`中取最大和最小的美丽值化妆品,同样累加并删除。 4. **输出结果**:打印两人最终的时尚值和美丽值总和。 这种方法高效地处理了每轮选择,利用`set`的自动排序和快速删除特性,确保总时间复杂度为O(n log n),适合处理大规模数据。 --- **相关问题**: 1. C++中`set`的底层实现是什么? 2. 如何高效地删除`set`中的最大和最小元素? 3. 在C++中,`pair`是如何进行比较的? 4. 如果属性值有重复,上述方法需要如何调整?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值