D — Race
题目大意:
贝西正在进行一场长度为K(1≤K≤109)米的赛跑。她刚开始以每秒0米的速度跑。在给定的一秒内,她可以把速度提高1米/秒,或者保持不变,或者降低1米/秒。例如,在第一秒,她可以把速度提高到1米/秒,然后跑1米,或者保持0米每秒,然后跑0米。贝西的速度永远不会降到0以下。
贝西总是跑向终点线,她希望在整数秒后完成(在这个整数秒内结束或超过终点线)。此外,她不想在终点线跑得太快:在贝茜跑完K米的那一刻,她希望她的速度不超过每秒X米(1≤X≤105)。贝西想知道当N(1≤N≤1000)个不同的X值时,她能多快跑完比赛。
输入
第一行包含两个整数K和N。
接下来的N行各包含一个整数X。
输出
输出N行,每行包含一个整数,表示贝西刚跑过终点时速度不大于X所需的最短时间。
题目分析:
想要时间最短,肯定是一直提升速度,那么就有两种情况发生:
(1) 提升速度还没到达x,路程已跑完。这时最短时间就是(最大速度时+是否有剩余路程(1 or 0) )。
例如:k=11,x=5
速度持续提升到4时,路程走了10,不能再提升到5,那么最大速度为4。这个剩余1的路程可以在速度为1时走多1秒(如果剩余2则在速度2多走1秒,以此类推)。
(2) 提升速度到了x,路程还没有走完。那么过程中速度时先增后减的变化,最短时间肯定是开始时尽量提速,后面尽量刚好以速度x过终点。欸,假设跑过终点后继续持续减速跑直到速度0,那么这个速度变化就像是对称的(当然,也可以减去前面x-1速度的路程,假设起点速度为x)。
例如:k=10,x=3 答案的速度依次为 1 1 2 3 3
依据上面思想,加上终点后的速度为 1 1 2 3 3 2 1(走完1速度即0),加上的那些速度走了3米
移动某几个速度变为 1 2 3 1 3 2 1,提升的最大速度为3,1到3走了6的路程,由于对称,1到3,3到1,共12米,减去加上去的3米,也就是9米,还有1米路程,这1米就是在速度为1时多走1秒。
代码实现:
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
LL k;
int n,x;
LL lj[100007]; //lj[i] 1到i的累加
void init()
{
lj[0] = 0;
for(int i=1; i<100003; i++)
{
lj[i] = lj[i-1]+i;
}
}
int main()
{
init();
scanf("%lld%d",&k,&n);
for(int i=0; i<n; i++)
{
int ans = 0;
scanf("%d",&x);
if(lj[x]>=k) //速度提升到x时跑完
{
for(int j=1; lj[j]<=k; j++) ans = j; //未跑过终点的最大速度
LL bbb = k-lj[ans]; //剩余路程
if(bbb>0) ans = ans+1; //没有刚好跑完,则在中间多一秒
printf("%d\n",ans);
}
else //速度提升到x时还没到终点
{
LL ker = k+lj[x-1]; //加上假设跑过终点后减速到0的路程
for(int j=1; lj[j]*2<=ker; j++) ans = j; //提升的最大速度
LL aaa = ker-lj[ans]*2LL; //剩余路程
if(aaa==0LL) ans = 2*ans-(x-1); //刚好跑完,减去跑过终点后的时间
else if(aaa<=ans*1LL+1) ans = 2*ans-(x-1)+1; //不超过最大速度+1,减去跑过终点后的时间,加上1秒
else ans = 2*ans-(x-1)+2; //超过最大速度+1,不能1秒跑完,所有加2秒
printf("%d\n",ans);
}
}
return 0;
}