Triangles are polygons with three sides and strictly positive area. Lattice triangles are the triangles all whose vertexes have integer coordinates. In this problem you have to find the number of lattice triangles in an M x Ngrid. For example in a (1 x 2) grid there are 18 different lattice triangles as shown in the picture below:
Input
The input file contains at most 21 sets of inputs.
Each set of input consists of two integers M and N ( 0 < M, N1000 ). These two integers denote that you have to count triangles in an (M x N) grid.
Input is terminated by a case where the value of M and N are zero. This case should not be processed.
Output
For each set of input produce one line of output. This output contains the serial of output followed by the number lattice triangles in the (M x N) grid. You can assume that number of triangles will fit in a 64-bit signed integer.
Sample Input
1 1 1 2 0 0
Sample Output
Case 1: 4 Case 2: 18
解题报告: 好吧,这题我看了解题报告。想了好几天,却卡在一个地方。我的想法是: 求三角形的数量,可以用C(m*n, 3)减去所有在同一条直线上的三点的情况数。枚举斜率求所有的情况,然后卡在这里……
这题和Highway那一题其实很像。我们需要求出所有三点共线的情况数。何时三点共线?当第三个点(x3,y3)与第一个点(x1,y1)的斜率和第二个点(x2,y2)与第一个点的斜率相同时。
换句话说,以(0,0)为起点,(2,2)点与(0,0),(1,1)点三点共线,因为gcd(2,2)=2,说明中间有一个点。
我们固定起始点和终点(保证无重复),计算当中间点不同时有多少种三点共线的情况,然后累加,得到(i,j)点中所有三点共线的情况。再累加,得到(0,0)到(i,j)点的点阵中所有的三点共线的情况。对称的原因,结果乘2。代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
LL sum[1111][1111];
LL C(LL n, LL m)
{
if(n<m) return 0;
LL res=1;
for(int i=0;i<m;i++)
res*=(n-i), res/=(i+1);
return res;
}
int gcd(int a, int b)
{
return b==0?a:gcd(b, a%b);
}
void init()
{
for(int i=2;i<=1000;i++)
for(int j=2;j<=1000;j++)
sum[i][j]=gcd(i, j)-1;
for(int i=2;i<=1000;i++)
for(int j=2;j<=1000;j++)
sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+sum[i][j];
for(int i=2;i<=1000;i++)
for(int j=2;j<=1000;j++)
sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+sum[i][j];
}
int cas=1;
void work(int n, int m)
{
printf("Case %d: %lld\n", cas++, C(m*n, 3) - C(n, 3)*m - C(m, 3)*n - sum[n-1][m-1]*2);
}
int main()
{
init();
int m, n;
while(~scanf("%d%d", &n, &m) && (m||n))
work(n+1, m+1);
}