CF1721C Min-Max Array Transformation

题链:cf luogu

Description

给你两个长度为 n 的数组 ab,存在一个长度为 n 的数组 d,满足 ai+di=bi,让你求对于每个 ai,找到可能匹配的最小和最大 bi,输出 biai 的最小和最大可能值。每个 ai 求得值相互独立,最小和最大值也相互独立。

Analysis

最小的应该很简单了,就是找到 b 中第一个不小于 ai 的数 bj,输出 bjbi。为了实现高效的查找,由于原本给出的 ab 即是非降的,可以使用二分查找,c++ 党亦可使用 lower_bound 函数。

难点在找最大,因为原数组 ab 非降,且长度均为 n,可以考虑如下思路:

从后向前遍历,我们任然通过二分找到 b 中第一个不小于 ai 的数 bj,当第一次发现 i=j 时,则 aian 必须匹配 bibn,此时 aian 均可与 bn 相匹配,但由于 d 非负,因此 a1ai1 不可能匹配到 bibn 中的任何一个数,记录此时匹配位置 lst=i=j

下一次再找到 i=j 时直接使 aialstblst 匹配,而 a1ai1 不可能匹配到 biblst 中的任何一个数,再记录新的 lst。直到遍历到开头。

综上所述,反映了分段思想,即通过分段处理来判断能否匹配、可能匹配的最大值。

Code

此处展示 c++ 党代码。

#include <stdio.h> #include <algorithm> const int N = (int)2e5 + 5; int n, a[N], b[N], c[N]; int main(void) { int t; for (scanf("%d", &t); t--; ) { scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); for (int i = 1; i <= n; ++i) scanf("%d", &b[i]); for (int i = 1; i <= n; ++i) { int l = std:: lower_bound(b + 1, b + 1 + n, a[i]) - b; //二分 printf("%d ", b[l] - a[i]); //最小直接输出 } putchar('\n'); int l, lst = n + 1; for (int i = n; i >= 1; --i) { l = std:: lower_bound(b + 1, b + 1 + n, a[i]) - b; //二分 if (l == i) { //即 Analysis 中所述 i = j for (int i = l; i < lst; ++i) c[i] = b[lst - 1] - a[i]; lst = l; //由于是倒序遍历,只能记录答案,后面再输出 } } for (int i = 1; i <= n; ++i) printf("%d ", c[i]); putchar('\n'); //打印最大 } return 0; }

The end. Thanks.

(路过点点


__EOF__

本文作者Miracle Hydrogen
本文链接https://www.cnblogs.com/dry-ice/p/cf1721c.html
关于博主:可耐拽冰!
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
posted @   Dry_ice  阅读(179)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示