原题链接: http://codeforces.com/contest/1455/problem/B
测试样例
input
5
1
2
3
4
5
output
1
3
2
3
4
题意: 在水平 O − x O-x O−x轴上,你起始位置在 0 0 0处,你的目标位置在 x x x处,现在你可以进行一个操作,在进行第 k k k次操作时,且你此刻位置在 y y y,你可以选择:
- 将坐标 y y y变为 y + k y+k y+k
- 将坐标 y y y变为 y − 1 y-1 y−1
问你到达 x x x的最小操作次数。
解题思路: 我们先这样想,假设我们一直是选择第一步操作,那么我们的坐标就是 1 + 2 + . . . 1+2+... 1+2+...,直到到达 x x x。那么我们就可以这样就假设,直到我们的坐标大于等于 x x x时就停止操作并记录此刻的 k k k。 此时我们就必须要清楚我们的偏移量即是 y − x y-x y−x。而我们想要的是 y = x y=x y=x。故我们需要补足这偏移量,而这也正是通过选择第二步操作来实现的,那么我们我们是直接选择第二步操作吗?答案是否定的,因为这肯定不是最优的,我们思考一下,如果我们在我们假设的这 1 1 1~ k k k的步骤中我们改变一步操作(设这个操作为 t t t),不进行第一步操作而去进行第二步操作那么我们这样会导致我们向左移了 t + 1 t+1 t+1。 那么实际上我们发现我们进行改写第一步操作会修改偏移量 2 2 2,第二步则 3 3 3…所以我们最后如果算出来的偏移量能否从高 ( k ) (k) (k)到低(2)减成 0 0 0,那么我们的操作次数就是 k k k,否则即是 k + 1 k+1 k+1。具体看AC代码。
AC代码
/*
*blog:https://blog.csdn.net/hzf0701
*邮箱:unique_powerhouse@qq.com
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*/
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
using namespace std;
typedef long long ll;
const int maxn=1e5;//数组所开最大值
const int mod=1e9+7;//模
const int inf=0x3f3f3f3f;//无穷大
int t,x;
void solve(){
int cnt=0,ans=0;
int k=1;
while(x>ans){
ans+=k;
k++;
cnt++;
}
int temp=ans-x;
per(i,k,1){
if(temp>=i+1){
temp-=(i+1);
}
}
cnt+=temp;
cout<<cnt<<endl;
}
int main(){
while(cin>>t){
while(t--){
cin>>x;
solve();
}
}
return 0;
}