学习C++从娃娃抓起!记录下USACO(美国信息学奥赛)备考青铜组别比赛学习过程中的题目,记录每一个瞬间。
附上汇总贴:USACO历年青铜组真题解析 | 汇总-CSDN博客
【题目描述】
Bessie 正在参加一场 K(1≤K≤10^9)米的跑步比赛。她从 0 米每秒的速度开始比赛。在每一秒中,她可以选择将她的速度增加 1 米每秒,保持速度不变,或者将她的速度减少 1 米每秒。例如,在第一秒中,她可以将她的速度增加到 1 米每秒,跑 1 米,或者保持她的速度 0 米每秒不变,跑 0 米。Bessie 的速度不会降低到小于零。
Bessie 始终朝着终点线的方向跑,她想要花费整数秒的时间完成比赛。此外,她不想在终点时跑得太快:在 Bessie 跑完 K 米的时刻,她希望她的速度不超过 X(1≤X≤10^5)米每秒。Bessie 想要对于 N(1≤N≤1000)个不同的 X 值知道她多快可以完成比赛。
【输入】
输入的第一行包含两个整数 K 和 N。
以下 N 行每行包含一个整数 X。
【输出】
输出 N 行,每行包含一个整数,表示 Bessie 完成比赛时的速度小于或等于 X 的情况下跑完 K 米需要的最小时间。
【输入样例】
10 5
1
2
3
4
5
【输出样例】
6
5
5
4
4
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int k, n, x;
ifstream filein("race.in");
ofstream fileout("race.out");
int main()
{
filein >> k >> n; // 输入k和n
while (n--) { // 遍历n次询问
filein >> x; // 输入x
long long presum = (long long)(x+1)*x/2; // 求出presum(细节处理,需要加上long long)
if (presum>=k) { // 如果presum已经超过了k
fileout << ceil(sqrt(2*k+0.25)-0.5) << endl; // 反向求
continue;
}
int l=0, r=(k-presum)/x; // 二分左值为0,右值为(k-presum)/x
if ((k-presum)%x!=0) { // 如果r不为整数,自增1(细节处理)
r++;
}
while (l<r-1) { // 二分查找
int m = (l+r)/2; // 中间点
int tot = k-presum-x*m; // tot为增加面积。(tot+presum+m*x)>= k
long long cmax=0; // 定义cmax,后面需要与tot比较
int up=m/2; // up取m的一半
if (m%2==0) {
cmax = (long long)up*up; // 增加的面积
} else {
cmax = (long long)(1+up)*up; // 增加的面积(细节处理)
}
if (cmax>=tot) { // 如果cmax大于等于tot,说明m设大了
r = m;
} else { // 否则说明设小了
l = m;
}
}
fileout << x+r << endl; // x是presum的时间,r为m这段的时间
}
return 0;
}
【运行结果】
10 5
1
6
2
5
3
5
4
4
5
4