CF1809E 题解
fast_photon · · 题解
0. 前言
没啥好说的。
Upd 2023.4.20 21:38 修正了线段举例的表述及 LaTeX。
Upd 2023.4.21 6:22 把题解改得正常了然后拿大号交。
1. 分析
首先不难注意到一点,两个容器的总水量不变。
这个也算是一个典型套路,记住就好。
我们假装将两个容器底部接通。
那么一次体积为
我们可以认为,在数轴上
而原点是 “分隔点”。
若干体积水可以理解为一条线段,挪水则是线段的左右滑动。但是:
- 线段不会挪出
[-a,b] 的区间,即容器的水最多是满的。 - 原点始终在线段上(含端点),即容器的水最少是空的。
考虑何种线段可以合并处理。例如,两个分别是左
即一系列的相邻两个左端点最初差
若当前状态符合这个定义,因为操作被拆分成了若干左
1 或右1 。
当左1 时,若若干线段受-a 限制。
则它们的左侧不可能有更多线段(否则超出-a 限制),此时右侧的线段因为平移量只有1 所以全部不受限。即左端进行了额外一格的吞并。
同理可以证明右1 的b 限制和左右的原点限制。
也就是只要算出左右的重叠长度即可。
2. AC Code
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define int long long
#define maxn 10005
#define maxv 1005
using namespace std;
int _, n, a, b, v[maxn], ans[maxv][maxv];
void work() {
int sum = 0;
cin >> n >> a >> b;
for(int i = 1; i <= n; i++) cin >> v[i], sum += v[i];
for(int w = 0; w <= a + b; w++) { //枚举线段长度
int l = max(a - w, 0ll), r = min(a + b - w, a); //因为显然数组不能访问负的位置,所以将左右中的限制和线段都向右平移 $a$。
int L = l, R = r;//初始状态的左端点上下界
for(int i = 1; i <= n; i++) {
r += v[i];
l += v[i];
r = min(r, R);
l = min(l, R);
r = max(r, L);
l = max(l, L);
}
if(l == r) {
for(int i = L; i <= R; i++) {
ans[a - i][i + w - a] = a - l;
}
continue;
}
for(int i = L; i < l - sum; i++) {
ans[a - i][i + w - a] = a - l;
}
for(int i = l - sum; i < r - sum; i++) {
ans[a - i][i + w - a] = a - (i + sum);
}
for(int i = r - sum; i <= R; i++) {
ans[a - i][i + w - a] = a - r;
}
//l-sum 和 r-sum 分别是当前合并后左端点上下界的线段在平移前的左端点值。因为这个表是要根据初始值绘制的。
}
for(int i = 0; i <= a; i++) {
for(int j = 0; j <= b; j++) {
cout << ans[i][j] << ' ';
}cout << endl;
}
}
signed main() {
ios_base::sync_with_stdio(false);
_ = 1;
while(_--) work();
}