视频加载失败

题解:AT_abc362_c [ABC362C] Sum = 0

题解:AT_abc362_c [ABC362C] Sum = 0
733 字
4 分钟
题解:AT_abc362_c [ABC362C] Sum = 0

很好写(15 min 解决)但不好讲(跟别人讲了 20 min)的写法 QwQ……


首先,咱先算出原式的范围。最小值(暂且记为 kk)的公式就是:

k=∑i=1NLik = \sum_{i = 1}^{N} L_i

就是每一个最小可能值的和。

同理,最大值(我记为 ww)的公式就是:

w=∑i=1NRiw= \sum_{i = 1}^{N} R_i

即最大可能值的和。

算这玩意儿有啥用呢?卡区间!

你说要是 k>0k > 0 或者 w<0w < 0,即最小都比 00 大或者最大都不到还能干成 00 吗?肯定不能啊!这种情况就是 No。

剩下的鉴于大家都是整数,而且可以随便变化,一定是 Yes(注:其实这就是零点存在定理:当一个函数 f 在 x∼yx \sim y 是连续时,如果 f(x)<0f(x) < 0 但 f(y)>0f(y) > 0,那么一定有 x<z<yx < z < y 满足 f(z)=0f(z) = 0)。

所以该咋构造呢?

我们可以以 kk 为基准,往 00 去凑。

具体来讲,就是:

Ansi={Ri (left>Ri−Li)Li+left (Ri≥left+Li)Ans_i = \begin{cases}R_i \ (left > R_i - L_i) \\ L_i + left \ (R_i \ge left + L_i)\end{cases}

其中 leftleft 表示到 00 的距离,也就是 0−k0 - k。说人话翻译一下就是:

  1. 能够直接凑完,那就直接凑完,然后就不用凑了。
  2. 凑不完,能凑多少是多少,记得更新一下后面要凑的数目

比如样例 11:

经计算,left=3left = 3,第一组(3∼53 \sim 5)最多凑个 22,那就凑 22,输出 55,还剩个 11 要凑。第二组(−4∼1-4 \sim 1)最多能凑个 55,但 11 就够了,输出 −3-3,不用凑了。最后一组,不用凑了,直接输出 −2-2。

算一下,5+(−3)+(−2)=5−3−2=05 + (-3) + (-2) = 5 - 3 - 2 = 0,满足条件。

注意:今天,你开 long long 了吗?


赛场 AC Code:

// Problem: C - Sum = 0
// Contest: AtCoder - Toyota Programming Contest 2024#7(AtCoder Beginner Contest 362)
// URL: https://atcoder.jp/contests/abc362/tasks/abc362_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
/*Code by Block_Fish*/
#include <bits/stdc++.h>
#define log printf
#define EPS 1e-8
#define INF 0x3f3f3f3f
#define FOR(i, l, r) for (ll(i) = (l); (i) <= (r); ++(i))
#define IOS \
ios::sync_with_stdio(false); \
cin.tie(nullptr); \
cout.tie(nullptr);
using namespace std;
typedef __int128 i128;
typedef long long ll;
typedef pair<ll, ll> PII;
const ll N = 2e5 + 10;
ll n, l[N], r[N], lft, suml, sumr;
template <typename T>
inline T read() {
T sum = 0, fl = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-') fl = -1;
for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - '0';
return sum * fl;
}
template <typename T>
inline void write(T x) {
if (x < 0) {
putchar('-'), write<T>(-x);
return;
}
static T sta[35];
ll top = 0;
do { sta[top++] = x % 10, x /= 10; } while (x);
while (top) putchar(sta[--top] + 48);
}
int main() {
n = read<ll>();
FOR(i, 1, n) l[i] = read<ll>(), r[i] = read<ll>(), suml += l[i], sumr += r[i];
if (!(suml <= 0 && sumr >= 0)) {
cout << "No";
return 0;
}
lft = 0 - suml; // 到0剩下的距离
cout << "Yes" << endl;
FOR(i, 1, n) {
if (l[i] + lft <= r[i]) {
cout << l[i] + lft << " ";
lft = 0;
} else {
cout << r[i] << " ";
lft -= r[i] - l[i];
}
}
return 0;
}

AC 记录~

理解万岁!

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
题解:AT_abc362_c [ABC362C] Sum = 0
https://www.leo2011.eu.org/posts/atc-abc362c/
作者
Block_Fish
发布于
2024-07-13
许可协议
SATA

评论区

Profile Image of the Author
Block_Fish
大胆假设,小心求证。——胡适
公告
网站全面重构,有问题欢迎联系积木鱼!
分类
标签
最新动态
站点统计
文章
56
分类
7
标签
17
总字数
84,805
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Netlify CI
博客版本
Firefly v6.16.8
文章许可
SATA

当前页面没有目录

文章目录

当前页面没有目录