D. Race
https://codeforces.com/group/5yyKg9gx7m/contest/270203/problem/D
分析:
因为他是每秒增加并以该速度前进的。最后要降到指定的速度以下,而且要刚好走完。可以把他想象成一个梯形,从1一直加到能加的最大值maxs,以maxs速度走一段后再速度一直降1。有指定降低的速度,就相当于梯形被截断一块,把他补上即可。
这样只考虑速度最高时和最后速度的情况就行(因为是对称的)。把res设为最高速度走的路和最后速度应该走的路。如果可以整除最高速度。那么在其中取一秒,由最后速度和随意一个速度凑成。否则再找怎么由最后速度凑成剩下的。
因为速度是不断加1,所以预处理一个等差数列,大概处理到1e5就差不多了。因为能加速到最大为maxs,所以,找到等差数列前maxs项和不超过k。
代码:
#include <stdio.h> #include <cstring> #include <algorithm> #include <cstring> #include <cmath> #include <vector> #include <iostream> #define min(x,y) x<y?x:y; using namespace std; typedef long long ll; const int maxn=1e5+6; const int INF=9e7; int main() { ll way[maxn]; way[0]=0; for(int i=1;i<=maxn;i++) { way[i]=way[i-1]+i; } int n; ll k; scanf("%lld%d",&k,&n); ll ans[maxn]; ll maxs=lower_bound(way,way+maxn,k)-way; if(way[maxs]!=k) maxs--; ans[maxs]=maxs; if(k!=way[maxs]) ans[maxs]++; for(int i=0;i<maxs;i++) ans[i]=INF; for(int i=1;i<maxs;i++) { ll m=k+way[i-1]; ll p; if(m%2==0) p=m/2; else p=m/2+1; ll s=lower_bound(way,way+maxn,p)-way; if(way[s]!=p) s--; for(int j=s;j>=i;j--) { ll res=m-2*way[j-1]+i; if(res%j==0) { ll an=2*(j-1)-i+1+res/j; if(ans[i]>=an) { ans[i]=an; } else break; } else { ll an=2*(j-1)-i+1+res/j-1; if(res%j<=i) an++; else an+=2; if(ans[i]>=an) { ans[i]=an; } else break; } } ans[i]=min(ans[i],ans[i-1]); } while(n--) { int sp; scanf("%d",&sp); if(sp<maxs) printf("%lld\n",ans[sp]); else printf("%lld\n",ans[maxs]); } return 0; }