如图所示的螺旋折线经过平面上所有整点恰好一次。
对于整点(X, Y),我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。
例如dis(0, 1)=3, dis(-2, -1)=9
给出整点坐标(X, Y),你能计算出dis(X, Y)吗?
思路
感觉这就是个模拟题,我们可以抓大放小
总体思路:
先走足够多次,到能够满足其中一个目标坐标的位置,再根据当前位置和目标点的差距,补偿步数即可
1.走到满足一个坐标:
如下图,可以看到都是两步两步地走的,即:走两次,变换步长,再走(不同颜色表示不同步长)
约定:以相同的步长走两步,为走一次
例:到点(2, -2)走了4次
并且可以发现,对于x或y,想要到达目标坐标值,走的次数可以由目标坐标值确定
对于x轴,想要达到x坐标:
如果x为负数,那么次数就是 -x*2 - 1
如果x为正数,那么次数就是 2*x
对于y轴,想要达到y坐标:
如果y为负数,那么次数就是 -x*2
如果y为正数,那么次数就是 2*x - 1
我们取目标x,y之中,需要走次数最大的,作为我们走的次数time
(因为要保证两个轴都能够道达)
走的次数和距离满足等差数列前n项和
次数 time:1,2,3,4
距离 dis :2,6,12,20
dis = (time + 1) * time
2.补偿步数:
如果按照上述思路,有可能会走过头,或者是走不够
这时候需要根据黑点的坐标,补偿步数,走过了就减,没走到就加
为了达到x=-2,我们走了三次,到达黑点,目标是黄点,显然走过了
为了到达y=2,我们走了3次,到达黑点,目标是黄点,显然走的不够多
代码
多组数据测试的运行结果:
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define iabs(x) ((int)fabs(x))
typedef long long ll;
int X, Y, x, y;
int main()
{
cin>>X>>Y
if(X==0 && Y==0)
{
cout<<"dis=0"<<endl;
continue;
}
ll sum = 0; // 步数和
int time = 0; // 走的次数
// 计算最少次数
if(X > 0)
{
time = max(time, 2*X);
}
else
{
time = max(time, 2*iabs(X) - 1);
}
if(Y > 0)
{
time = max(time, 2*Y - 1);
}
else
{
time = max(time, 2*iabs(Y));
}
// 计算步数(等差数列求和)
sum = time * (time+1);
// 计算走time次之后的最终坐标(规律同上面那个图)
if(time%2 == 0)
{
x = time/2;
y = -1*time/2;
}
else
{
x = -1*(time+1)/2;
y = (time+1)/2;
}
// 步数补偿:如果点不在整步数点上,分类讨论
if(x==X && y==Y)
{
cout<<"dis="<<sum<<endl;
}
// x到了y没到
else if(x==X && y!=Y)
{
// x > 0,表示正在往下走
if(x > 0)
{
sum += y - Y;
}
// x < 0 表示正在往上走
else
{
sum -= y - Y;
}
cout<<"dis="<<sum<<endl;
}
// x没到y到了
else if(x!=X && y==Y)
{
// y > 0 表示正在往右走
if(y > 0)
{
sum -= x - X;
}
// y < 0 表示正在往左走
else
{
sum += x - X;
}
cout<<"dis="<<sum<<endl;
}
return 0;
}
递增的测试样例
0 0
-1 0
-1 1
0 1
1 1
1 0
1 -1
0 -1
-1 -1
-2 -1
-2 0
-2 1
-2 2
-1 2
0 2
1 2
2 2
2 1
2 0
2 -1
2 -2
1 -2
0 -2
-1 -2
-2 -2
-3 -2
-3 -1
-3 0
-3 1
-3 2
-3 3