Educational Codeforces Round 134 (Rated for Div. 2)

1|0基本情况

AB秒了。

C搞了一个错的二分答案,虽然过样例了。

2|0C. Min-Max Array Transformation

2|1错误分析

没有进一步推导性质,而是觉得数据单调递增估计是二分,然后就无脑写,实际上 check 的正确性没有保证。

bool check(int ind, int now) { if (ind == now) return true; if (b[ind] < a[now]) return false; if (ind == 1) return true; return b[ind - 1] >= a[ind];//并不严谨 } void solve() { int n; std::cin >> n; for (int i = 1; i <= n; i++) std::cin >> a[i]; for (int i = 1; i <= n; i++) std::cin >> b[i]; for (int i = 1; i <= n; i++) { int l = 0, r = n, ans = 0; while(l <= r) { int mid = l + (r - l >> 1); if (check(mid, i)) r = mid - 1, ans = mid; else l = mid + 1; } if (ans != 0) std::cout << b[ans] - a[i] << " "; else std::cout << b[i] - a[i] << " "; } std::cout << std::endl; for (int i = 1; i <= n; i++) { int l = 0, r = n, ans = 0; while(l <= r) { int mid = l + (r - l >> 1); if (check(mid, i)) l = mid + 1, ans = mid; else r = mid - 1; } if (ans != 0) std::cout << b[ans] - a[i] << " "; else std::cout << b[i] - a[i] << " "; } std::cout << std::endl; }

2|2正确思路

1|0题意

有两个序列 a,b。对于每个 ai,你需要对 b 进行重排,使得 k,bkak0。问这时 biai 最小、最大分别可能是多少。

多组询问,n2×105

下面的讨论,记 c 为重排后的 b

1|0task1

最小其实很好做。如果没有确定的思考方向,可以发挥 CF 上非常实用的盲猜法。

对于 ai 而言,单纯要让重排后 ciai 最小,可以直接让 ci 等于b 中大于等于 ai 且最小的数,即后继。

这个结论是对的。直接输出后继就完了,接下来我给个证明。

因为题目保证有解,所以最起码对于原来的 a,bk,akbk

我们令 bjbai 后继,此时定有 bjbi,所以 ji

然后考虑这样的构造(c 为重排后的 b):

ck={bkk[1,j)bk+1k[j,i)bjk=ibkk(i,n]

1|0task2

有一个关键性质,就是 jicj 的选择不会影响 ci 的选择。原因是根据上面 k,bkakb1i1 可以解决 a1i1,不会影响 ai

所以如果你想让单个的 ciai 最大,只需要解决 i+1n 的影响即可。

然后就是一个贪心的思想。如果 ci 尽量的大,那么就要让 ci+1n 都尽量的小。

所以我们用一个 set 存下所有的 b,倒序遍历 a,然后删除 setai 的后继。删除之前的 set 的最大值就是答案。

1|0code

void solve() { int n; std::multiset<int> st; std::cin >> n; for (int i = 1; i <= n; i++) std::cin >> a[i]; for (int i = 1; i <= n; i++) std::cin >> b[i], st.insert(b[i]); for (int i = 1; i <= n; i++) std::cout << *std::lower_bound(b + 1, b + n + 1, a[i]) - a[i] << " "; std::cout << std::endl; for (int i = n; i >= 1; i--) { d[i] = *std::prev(st.end(), 1); st.erase(st.lower_bound(a[i])); } for (int i = 1; i <= n; i++) std::cout << d[i] - a[i]<< " "; std::cout << std::endl; }

这里用到了multiset


__EOF__

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