Codeforces #280 (Div.2 A~E)

本文提供了 Codeforces Round #280 (Div.2) 的五道题目的详细解题思路与代码实现,包括堆金字塔的高度计算、灯照亮区间的最小半径、通过考试所需的最少文章数量、打怪游戏中击杀归属判断以及二维循环空间中最大覆盖点数的起点选择。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

比赛地址

Codeforces Round #280 (Div. 2)


492A. Vanya and Cubes

题意:

Vanya要堆金字塔,第1层要1个方块,第2层要1+2个,第3层要1+2+3个,以此类推。现在Vanya有n个方块,求能堆的金字塔的最大高度。

n < 10 ^ 4。

题解:

设金字塔高度为h,则需要的积木数为\sum_{i = 1} ^ {h} {\sum_{j = 1} ^ {i} {j}} = \sum_{i = 1} ^ h {i * (h + 1 - i)} = (h + 1) * \sum_{i = 1} ^ h {i} - \sum_{i = 1} ^ h {i ^ 2} = h * (h + 1) * (h + 2) / 6,h大约为O(n ^ (1 / 3))级别,直接枚举即可,不写公式也可以。

时间复杂度O(n ^ (1 / 3))。

代码:

#include <cstdio>
int n, a, b, c;
int main()
{
	scanf("%d", &n);
	while(c <= n)
	{
		++a;
		b += a;
		c += b;
	}
	printf("%d\n", --a);
	return 0;
}

492B. Vanya and Lanterns

题意:

有一个数轴,数轴上区间[0, l]中有n个灯笼,对于一个给定的半径D,一个灯笼若在x可以照亮的范围是[x - D, x + D],请你求出最小的D,使得区间[0, l]每一点至少被一个灯笼点亮,答案误差不超过10^(-9)。

n <= 1000, l <= 10 ^ 9。

题解:

实际上我们只用考虑相邻的两个灯笼可以笼罩的范围,相邻的两个灯笼必须能笼罩二者之间的每一个点,不妨对灯笼按坐标排序,考虑任意两个相邻的灯笼距离为k,则2*D>=k,再考虑上端点附近的灯笼必须笼罩端点即可。(精度问题不是问题)

时间复杂度O(nlogn)。

代码:

#include <cstdio>
#include <algorithm>
using namespace std;
int n, l, a[2333];
double ans;
int main()
{
	scanf("%d%d", &n, &l);
	for(int i = 0; i < n; ++i)
		scanf("%d", a + i);
	sort(a, a + n);
	ans = max(a[0], l - a[n - 1]);
	for(int i = 1; i < n; ++i)
		ans = max(ans, (a[i] - a[i - 1]) / 2.0);
	printf("%.10f\n", ans);
	return 0;
}

492C. Vanya and Exams

题意:

Vanya希望通过n场考试并顺利拿到学位,已知通过的要求是n场考试平均分超过avg,每场考试得分不得超过r,现在Vanya在每场考试已有ai点成绩,如果想相应地提升1分,需要多写bi个文章,求拿到学位最少需要多写多少文章。

n <= 10 ^ 5。

题解:

因为1分对应一些文章,所以我们可以考虑贪心解决,首先可以算出来还需要提升的总点数,不妨将考试按bi排序,按照bi从小到大选择还没有到达最高分的考试进行补助,算出的答案必定是最少的。

时间复杂度O(nlogn)。

代码:

#include <cstdio>
#include <algorithm>
using namespace std;
int n, r, avg;
long long res, ans;
struct Node
{
	int a, b;
	bool operator < (const Node &x) const
	{
		return b < x.b;
	}
} e[233333];
int main()
{
	scanf("%d%d%d", &n, &r, &avg);
	for(int i = 0; i < n; ++i)
	{
		scanf("%d%d", &e[i].a, &e[i].b);
		res += avg - e[i].a;
	}
	sort(e, e + n);
	for(int i = 0; i < n && res > 0; ++i)
		if(r - e[i].a > 0)
		{
			long long k = min(res, (long long)r - e[i].a);
			res -= k;
			ans += k * e[i].b;
		}
	printf("%I64d\n", ans);
	return 0;
}

492D. Vanya and Computer Game

题意:

Vanya和他的好友Vova开始玩打怪游戏,怪物有n只,每只有ai点血量,角色打一下怪物可以使怪物掉1点血,Vanya每1/x秒会打一下怪物,而Vova则是每1/y秒,Vanya想知道每只怪物是谁最后打死的,以便计分。(考虑同时打中)

n <= 10 ^ 5, x, y <= 10 ^ 6, ai<= 10 ^ 9。

题解:

其实可以将题目转化为,Vanya每y秒打一下怪物,而Vova每x秒打一下怪物,这样结算怪物是谁打死的结果不会变,则我们可以二分预测是第几秒恰好打死怪物,从而判断最终杀怪属于谁。

代码:

#include <cstdio>
int n, x, y, a;
int main()
{
	scanf("%d%d%d", &n, &x, &y);
	while(n--)
	{
		scanf("%d", &a);
		long long L = 0, R = 1e15, M;
		while(L < R)
		{
			M = L + R >> 1;
			if(M / x + M / y < a)
				L = M + 1;
			else
				R = M;
		}
		if(L % x == 0 && L % y == 0)
			puts("Both");
		else
			puts(L % y == 0 ? "Vanya" : "Vova");
	}
	return 0;
}

492E. Vanya and Field

题意:

有一个二维循环空间,横纵坐标的取值范围均为[0,n),现在空间里有m个点,规定一个运动向量{dx, dy},运动向量描述的是从(x, y)到((x + dx) mod n, (y + dy) mod n)的运动,请你选择一个起点,使得按照运动向量运动回这个点时经过的点数最多。

n <= 10 ^ 6, m <= 10 ^ 5。

题解:

对于一个(x, y)来说,它和((x + dx) mod n, (y + dy) mod n)、((x + 2 * dx) mod n, (y + 2 * dy) mod n)……((x + (n - 1) * dx) mod n, (y + (n - 1) * dy) mod n)都在同一个运动轨迹上,不妨从中选出一个横坐标为0的点,则其他的点也可以用这个点得出。那么当横坐标为0,纵坐标不同时,其实描述的是不同起点但是相似的运动轨迹。所以可以预先处理出运动轨迹关于y的函数,然后将那m个点转化为横坐标为0的点进行统计,从而得出答案。

时间复杂度O(n + m)。

代码:

#include <cstdio>
int n, m, dx, dy, f[2333333], cnt[2333333], ans[3];
int main()
{
	scanf("%d%d%d%d", &n, &m, &dx, &dy);
	for(int i = 0, x = 0, y = 0; i < n; ++i)
	{
		f[x] = y;
		x += dx;
		if(x >= n)
			x -= n;
		y += dy;
		if(y >= n)
			y -= n;
	}
	for(int x, y; m; --m)
	{
		scanf("%d%d", &x, &y);
		y -= f[x];
		if(y < 0)
			y += n;
		++cnt[y];
		if(ans[0] < cnt[y])
		{
			ans[0] = cnt[y];
			ans[1] = x;
			ans[2] = y + f[x];
			if(ans[2] >= n)
				ans[2] -= n;
		}
	}
	printf("%d %d\n", ans[1], ans[2]);
	return 0;
}

小记

人学多了总是容易想复杂,要及时复习总结;阅读能力有待加强,手速有待加强。

### 关于Codeforces Round 925 Div. 3 的题目及解析 #### A. Plus One on the Subset 在这个问题中,给定一个整数序列 \(a_1, a_2, \ldots, a_n\) 和若干次操作。每次可以选择任意子集并将这些位置上的元素增加一。目标是最少的操作次数使得所有元素都变成相同的值[^1]。 ```cpp #include <iostream> using namespace std; int main() { int t; cin >> t; while (t--) { int n; cin >> n; bool all_same = true; int first_value; cin >> first_value; for (int i = 1; i < n; ++i) { int temp; cin >> temp; if (temp != first_value) all_same = false; } if (all_same || n == 1) cout << "0\n"; else cout << "1\n"; } } ``` 这段代码通过判断输入数组中的所有元素是否已经相同来决定最少需要几次操作可以完成任务。如果所有的数值一开始就相等,则不需要任何改变;如果有不同的数值存在,则只需一次操作就可以让整个集合内的数字变得一致。 #### B. Multiply by Two, Divide by One 此题要求处理一系列由两个正整数构成的询问,对于每一个询问给出的结果是能否仅利用两种变换——将当前数翻倍或是除以二(当且仅当该数为偶数时),最终达到另一个指定的目标值。 为了实现这一点,可以从终点反向推导回起点,在每一步尝试逆运算直到回到起始状态或者发现不可能的情况为止。具体来说就是不断地执行减半(如果是奇数则无法继续)以及加上其一半的过程,直至到达原点或确认不可达性。 #### C. Make It Increasing 这个问题的任务是在不违反特定条件下尽可能多地保留原始数组里的项的同时构建一个新的严格递增序列。允许的操作是从已有的列表里移除某些成员而不改变其余部分相对顺序。 一种有效的策略是对初始数据先做预处理排序之后再逐一遍历比较相邻两项之间的关系,以此为基础做出取舍决策。这样做的好处是可以快速定位哪些地方出现了重复或者是不符合增长趋势的地方,并据此调整方案。 #### D. Yet Another Array Partitioning Problem 本题涉及到了如何分割一个长度固定的整型数组成多个连续片段的问题,目的是最小化各分段内部最大差值之和的最大可能值。这实际上是一个经典的动态规划问题变种版本之一。 解决方法通常涉及到定义合适的DP表格用于记录中间计算结果以便后续查询使用。这里的关键在于合理设计转移方程从而能够高效求得最优解路径。同时还需要注意边界条件设定以免造成逻辑错误影响整体性能表现。 #### E. The Strongest Build 针对这一挑战,背景设置在一个虚拟编程竞赛平台之上,参赛者们被鼓励提交自己的解决方案参与评分竞争。然而有趣的是,评判标准并非单纯基于运行效率而是取决于所选算法复杂度级别与实际消耗资源量之间是否存在显著差异作为奖励依据。 因此解答此类问题往往需要综合考量时间空间开销等因素的影响程度,进而挑选出最适宜当下环境状况的最佳实践方式来进行编码实现。此外还需特别留意特殊测试用例的存在可能性及其应对措施安排等问题细节之处。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值