题目:

如图p1.png所示的螺旋折线经过平面上所有整点恰好一次。
对于整点(X, Y),我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。
对于整点(X, Y),我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。
例如dis(0, 1)=3, dis(-2, -1)=9
给出整点坐标(X, Y),你能计算出dis(X, Y)吗?
【输入格式】
X和Y
X和Y
对于40%的数据,-1000 <= X, Y <= 1000
对于70%的数据,-100000 <= X, Y <= 100000
对于100%的数据, -1000000000 <= X, Y <= 1000000000
对于70%的数据,-100000 <= X, Y <= 100000
对于100%的数据, -1000000000 <= X, Y <= 1000000000
【输出格式】
输出dis(X, Y)
输出dis(X, Y)
【样例输入】
0 1
【样例输出】
3
3
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
解题思路:
看到这道题时发现,其可以看作是
以原点为质心的缺一个角的正方形构成,那么每个点的位置与dis一定是有函数关系的。
最适合寻找函数关系的点:第一象限内满足y=x的点(因为最特殊,又非负方便计算),写出x、y、dis的关系:
dis(1, 1) = 2 + 1 + 1; dis(2, 2)=4 + 3 + 3 + 2 + 2 + 1 + 1; dis(3, 3) = 6 + 5 + 5 + 4 + 4 + 3 + 3 + 2 + 2 + 1 +1;
即第一个加数为2i,只出现一次,而后递减的值,都出现两次。
得出结论:
dis(i, i) = (2 * n + 2 * (n-1) + …… + 2 + 2 + 1 + 1)
= 4 * i * i;
那么余下的点,皆可以根据与(i, i)的相对关系得出,划分的方式不唯一,以下是我的划分:
根据划分,代码如下
int dis(int x, int y)
{
int r; // 正方形边长的一半
if (x == y && x >= 0)return 4 * x * x; // 1. y=x线上,x非负
if (y > 0) // 2. x轴上方的,延长到右上角
{
r = abs(x) > abs(y) ? abs(x) : abs(y);
return 4 * r * r - abs(x - r) - abs(y - r); // 减去延长部分
}
if (y == 0) // 3. x轴上的(除原点)
{
r = abs(x);
if (x > 0)return 4 * r * r + r;
return 4 * r * r - 3 * r;
}
if (y < 0) // 4. x轴下方的,分为左侧竖直(有倒钩)和右下(无倒钩)
{
if (y <= x + 1) // 4.1 右下(无倒钩)
{
if (y == x + 1)r = 0 - y;
else r = abs(x) > abs(y) ? abs(x) : abs(y);
return 4 * r * r + abs(x - r) + abs(y - r);
}
if (y > x + 1) // 4.2 左侧竖直(有倒钩)
{
return 4 * r * r + (2 * r) + (2 * r + 1) + (y - (-r));
}
}
}