504 Square on the Inside
四边形 ABCD,各点位于四个坐标轴上,坐标分别是 ,其中 并且 都是整数。
比如 , 四边形 ABCD 共有 256 种情况。256 个四边形当中,有 42 四边形精确地包含平方个数目的网格点(坐标为整数)。
如果 , 有多少个四边形包含平方个数目的点呢?
对于现代计算机而言,遍历 其实是很快的一件事情,如果对于每一个四边形而言,如果能在常数量级得到包含点的个数,然后常数量级知道它是不是平方数,那么就基本能在 这个量级搞定这个问题。
那么如何知道四边形里面点的个数呢?
预先存下来。显然不是预先存下来每个四边形的点的个数,这不就是我们要的结果嘛。我们存储直角三角形的内部点的个数。
static private int[,] NumbersOfInsideVector = new int[M + 1, M + 1];
for (int i = 1; i <= M; i++)
{
for (int j = 1; j <= i; j++)
{
int result = GetInsideVector(i, j);
NumbersOfInsideVector[i, j] = result;
NumbersOfInsideVector[j, i] = result;
}
}
private static int GetInsideVector(int a, int b)
{
int count = 0;
for (int i = 1; i <= a - 1; i++)
{
int yi = b - b * i / a;
count += (yi - 1);
}
return count;
}
有了直角三角形内部点数,计算 ABCD 四边形内部点数就非常容易了。
private static int GetNumberOfVector(int a, int b, int c, int d)
{
int number = a + b + c + d + -3;
number += NumbersOfInsideVector[a, b];
number += NumbersOfInsideVector[b, c];
number += NumbersOfInsideVector[c, d];
number += NumbersOfInsideVector[d, a];
return number;
}
最后就是遍历每一个可能的情况。
long count = 0;
for (int d = 1; d <= M; d++)
{
for (int c = 1; c <= M; c++)
{
for (int b = 1; b <= M; b++)
{
for (int a = 1; a <= M; a++)
{
int numberOfVector = GetNumberOfVector(a, b, c, d);
int sqrt = (int)Math.Sqrt(numberOfVector);
if (sqrt * sqrt == numberOfVector)
{
count++;
}
}
}
}
}
return count;
以上是 2016 年 2 月做题时的思考,其实当时也应该能想到, 交换值不影响最后结果,不过要考虑各种情况的话,太复杂。
简单的考虑两种情况,。当 时,计算出结果,将其乘以 2,然后加上 时的结果即可。
代码虽然略微冗长,但是提速了一倍。
for (int d = 1; d <= M; d++)
{
for (int c = 1; c <= M; c++)
{
for (int b = 1; b <= M; b++)
{
for (int a = 1; a < b; a++)
{
int numberOfVector = GetNumberOfVector(a, b, c, d);
int sqrt = (int)Math.Sqrt(numberOfVector);
if (sqrt * sqrt == numberOfVector)
{
count++;
}
}
}
}
}
count *= 2;
for (int d = 1; d <= M; d++)
{
for (int c = 1; c <= M; c++)
{
for (int b = 1; b <= M; b++)
{
int numberOfVector = GetNumberOfVector(b, b, c, d);
int sqrt = (int)Math.Sqrt(numberOfVector);
if (sqrt * sqrt == numberOfVector)
{
count++;
}
}
}
}