2021.4.28 校内模拟赛游记

水到爆的一场模拟赛,但是因为代码丢失题意不清等奇怪原因就啥也没写出来。

A

水题,但题目就是不告诉你 sis_i 的范围是什么,让你自己猜。

我猜它非常大,于是把二分的边界设置为 2602^{60}, 结果没有注意到中间需要加 10001000 次,所以顺利溢出了。

其实是检查单执行不彻底,没有注意到 range 的问题,不然不论怎样也不能让这里溢出啊。

然后发生了 严重事故征候

在进行文件测试的时候突然跳出来弹窗说磁盘上的已经改变,要不要重新加载,被我误操作了确定,然后代码消失的一干二净,哪也找不回来了。

NTSB 第一时间展开了调查, 发现极有可能是文件操作中后缀名写成了 cpp 所致,程序直接覆盖了自己的源代码。而且 dev 没有办法撤回这样子的操作,所以代码就丢失了。

在最终报告中,NTSB 建议, 以后的代码都得在修改过整个文件夹备份了,这样不仅不怕覆盖丢失的问题,有些题目改炸了还可以整个回滚。

B

这题其实挺好的。

在一个数组中取 mm 段,第 ii 段长 did_i 且必须经过 bib_i, 求最大取出的数字之和。

开始以为是贪心,因为乍一看会有后效性。但贪心很容易构造出反例,于是又来想 dp, 加了一维以解除后效性。

f[i][j]f[i][j] 表示前 ii 个,最后的位置在 jj 的最优方案,然后再来个 kk 以供转移,看上去这不但是三维的,而且每一都是十万级别的,似乎没救了。

但其实不然,因为 jjkk 都有限制,所以总状态数其实是只有 nn 个的,同理,转移加起来也只有 nn 个,所以这个看似暴力不可过的其实就是正解。

为了实现方便,后来修改了状态, jj 代表是距离 ii 这个的末尾左边限制的距离。

代码。

#include <cstdio>
#include <vector>
const int N = 100005;
std::vector<int> f[N];
int n, m, sum[N], b[N], d[N], L[N], R[N], ans;
int main() {
	freopen("fish.in", "r", stdin);
	freopen("fish.out", "w", stdout);
	
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%d", &sum[i]), sum[i] += sum[i-1];
	scanf("%d", &m);
	for(int i = 1; i <= m; i++) scanf("%d%d", &b[i], &d[i]);
	b[m+1] = n+1;
	for(int i = 1; i <= m; i++) 
		L[i] = std::max(L[i-1]+d[i], b[i]), R[i] = std::min(b[i]+d[i]-1, b[i+1]-1);
	f[0].push_back(0); 
	for(int i = 1; i <= m; i++) 
		for(int j = L[i]; j <= R[i]; j++) {
			int k = f[i-1].size()-1;
			while(L[i-1] + k >= j - d[i] + 1) k--;
			f[i].push_back(0); 
			int now = f[i].size()-1;
			for( ; k >= 0; k--) f[i][now] = std::max(f[i][now], f[i-1][k]);
			f[i][now] += sum[j] - sum[j-d[i]];
	}
	for(int i = 0; i < (signed)f[m].size(); i++) ans = std::max(ans, f[m][i]);
	printf("%d", ans);
	return 0;
}

C

一切都是没有读清题目的锅。

题中啥 “跳到另一个电梯上”, 我还以为是直接电梯不停就过去了呢……好呆啊。

然后赛场上想了好久的做法,进行了一波细致的操作最终使它能过,但好像还是没有考虑向下走的情况,于是样例都没有过。

赛后补题的时候也没发现渔代码里的小问题。

D

水题。

【模板】Floyd 最短路。