覆盖
在 的坐标轴上有 个区间,第 个区间为 。现在你需要去掉一部分区间,使区间 与任意一个原本的区间不重叠。第 个区间删去代价为 ,求满足条件需要的最少代价。
首先,我们对区间以 为关键字从小至大进行排序,然后枚举 ,尝试答案区间为 需要的代价。由于 ,因此只有 的区间 可能会与 重叠。但是,我们发现这里重叠的标准是 是否小于 ,不妨在 上面下功夫。
新建另一个区间序列 ,将 赋值为 ,对 以 为关键字从小至大排序,此时我们就可以极快地通过二分求出哪一段的 了。此时我们发现当 时即使 也不会与我们的答案区间重叠,而原序列又是按照 进行排序的,因此我们直接新建变量满足 的区间 记录下来,求答案时需要减去。
最后对于所有的答案区间进行求值即可。时间复杂度 。注意 也是一个可选的答案区间,不能忽略,否则会失分。
#include <fstream>
#include <algorithm>
using namespace std;
using LL = long long;
const LL kMaxN = 1e5 + 5;
ifstream cin("cover.in");
ofstream cout("cover.out");
struct Interval {
LL l, r, p;
bool operator<(const Interval &that) {
return l < that.l;
}
} a[kMaxN], b[kMaxN];
LL p[kMaxN], n, w, c, sub, ans = 1e18;
LL calc(LL x) {
LL y = lower_bound(b + 1, b + n + 1, Interval{x, x, x}) - b - 1;
return p[y] - sub;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n >> w >> c;
for (LL i = 1; i <= n; i++) {
cin >> a[i].l >> a[i].r >> a[i].p;
b[i] = a[i];
}
sort(a + 1, a + n + 1, [](auto a, auto b) { return a.r < b.r; });
sort(b + 1, b + n + 1);
for (LL i = 1; i <= n; i++) {
p[i] = p[i - 1] + b[i].p;
}
ans = min(ans, calc(c));
for (LL i = 1; i <= n; i++) {
if (a[i].r + c <= w) {
sub += a[i].p;
ans = min(ans, calc(a[i].r + c));
}
}
cout << ans << '\n';
return 0;
}分发传单
最开始有 个 代生物。有 秒的时间可以让他们工作,第 代生物可以进行如下工作:花费 秒分发 张传单或花费 秒繁殖一个第 代的生物。多个生物可以同时工作,求 秒内可以分发的传单的数量的最大值。
题目完全看懂了,但是对于小至 的数据仍然毫无头绪,代码都没输入,文件都没有创建,本题成功获得 分。
后记:XBC 是机房内唯一一个使用 dp 的,获得 分,本机房最高分。

绘画
有 个格子,进行 次涂色,第 将任意连续 个格子染黑,若已经被染黑则颜色不变。求最后得到不同的结果的数量,答案为 取模。
采用最垃圾的手段进行骗分。对于 的特殊情况,也就是只会涂一次颜色,那么显然不会出现任何一个格子被重复填色的情况,因此答案即为 。成功获得 分。
后记:HHC 推公式 AC 掉了 的所有测试点,太巨了。
三角覆盖
给出一个直角边长为 的等腰直角三角形点集,共有 行,第 行的点为 。
有 次覆盖操作,每次覆盖一个等腰直角三角形区域内的点,第 次给出 个数 ,表示对于 ,点 被覆盖了。
随后给出 次询问操作,询问一个等腰直角三角形区域内未被覆盖的点数,第 次给出 个数 ,表示询问所有 ,点 有多少未被覆盖。
采用差分+前缀和的方式对于 的数据进行处理。
当 较小的时候,我们可以对于每一次处理都枚举每一行,但是不能枚举修改的三角形当中的每一个点。因此不难想出对于每一行进行序列差分。
但是我们需要考虑的很重要一个点,就是我们的差分是对一个区间的每一个元素进行相加,而非将区间内的每一个元素标记为 。这该怎么整呢?
实际上,我们还是正常地进行差分(区间都加 ),但是利用前缀和还原之后对于每一个不为 的元素其实就是 (原本的值代表它被标记了几次,而只要被标记了正整数次就是被覆盖),否则为 。
然后再进行一次每行的前缀和。这样子我们的查询操作也能做到 。该算法的总时间复杂度为 ,成功获得 分。