比赛地址
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;
}
小记
人学多了总是容易想复杂,要及时复习总结;阅读能力有待加强,手速有待加强。