Edu42

1|0基本情况

B 题目读假卡了快半小时,以后一定要彻底读清楚题目,分析好每一种情况再写代码。

D 想了一个解法,但无法保证答案有序,之后思维就死在了那个解法上无法变更。

2|0D. Merge Equals

Problem - D - Codeforces

一失足成千古恨,再回頭是百年身

2|1Mycode

map維護序列,然后能和成就尽量合成

但是答案无法保证顺序符合题目操作后的顺序

void solve() { int n; std::cin >> n; std::map<i64, int> cnt; for (int i = 0, x; i < n; i++) { std::cin >> x; cnt[x]++; } auto it(cnt.begin()); while (it != cnt.end()) { auto&[x, y](*it); if (y & 1) { ++it; if (y > 1) { cnt[1LL * x * (y - 1)]++; } } else { cnt[1LL * x * (y)]++; it = cnt.erase(it); } } std::cout << sz(cnt) << '\n'; for (auto&[x, _] : cnt) {std::cout << x << ' '; } std::cout << '\n'; }

2|2300Iq

只有直接模拟原操作才能保证答案的有序,因为从小到大按顺序处理每个数字,处理完之后不会重复处理,所以复杂度其实是 O(n)​ 的,用 std::map 或者优先队列实现都是可以的

直接模拟的过程中维护合成的新数的下标即可。

void solve() { int n; std::cin >> n; std::map<i64, std::set<int>> cnt;//set维护该数字对应的下标,利用set的特性保证每次取出来的下标都是题目要求的最靠前的 std::vector<i64> a(n); for (int i = 0; i < n; i++) { std::cin >> a[i]; cnt[a[i]].insert(i); } for (auto&[x, S] : cnt) { while (sz(S) > 1) {//直接模拟过程 int t1(*S.begin()); int t2(*(++S.begin())); a[t2] += a[t1]; a[t1] = -1;//表示这个数被合成了,删除 S.erase(t1); S.erase(t2); cnt[a[t2]].insert(t2);//对合成的新数加入对应的下标,这一步保证了答案的有序 } } std::vector<i64> res; for (auto& x : a) if (x != -1) { res.push_back(x); } std::cout << sz(res) << '\n'; for (auto& x : res) std::cout << x << ' '; std::cout << '\n'; }

3|0E

Problem - E - Codeforces

一道有质量的构造题。

一种错误的做法是,直接将相邻的 P,BP,R 相连。

但其实两个 P 之间的边是可以共用的,就出现了多种连边方案。

以下讨论 P,R 的情况,因为 P,B 同理。

对于最左端的 P 左边的 R 点,直接与该 P 点相连,没有其它方案。对于最右端的 P 点右边的 R 点同理。

接下来对于两个相邻的 P 点以及它们之间的 R 点,有两种连法。

一是与错误解法相同,直接连相邻的 P,R 点即可,代价等于这两个 P 点的距离。

二是先连两个 P 点,然后将其间相邻的 R 点连接为两个连通块,分别接到两个 P 点上。R 点的两个连通块在距离最长的两个 R 点间分割。

每对相邻的 P 点都可看作一个独立的小块计算代价并选择最优的方案,最后考虑 P,B 即可。

void solve() { int n; i64 ans{}; std::cin >> n; bool R{}, B{}, P{}; i64 lastR{}, lastB{}; i64 cnt1{}, cnt2{}, cnt3{}; for (int i = 0; i < n; i++) { i64 dis; char c; std::cin >> dis >> c; if (c == 'P' or c == 'R') { if (R) { ans += dis - lastR;//把相邻的R连边 cnt1 = std::max(cnt1, dis - lastR);//维护P与R连通块相连的最小距离 } R = true; lastR = dis; } if (c == 'P' or c == 'B') { if (B) { ans += dis - lastB;//把相邻的B连边 cnt2 = std::max(cnt2, dis - lastB);//维护P与B连通块相连的最小距离 } B = true; lastB = dis; } if (c == 'P') { if (P) {//把两个P连起来 ans += std::min(0LL, dis - cnt1 - cnt2 - cnt3); } P = true; cnt1 = cnt2 = 0; cnt3 = dis; } } std::cout << ans << '\n'; }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/18102002.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示