Codeforces #280 (Div.2 A~E)

比赛地址

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;
}

小记

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

你可能感兴趣的:(排序,模拟,数学,贪心,二分)