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 N grid. 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
关键是如何去掉不合条件的。首先三角形的三个点的分布只有两种情况,两个点在同一条水平线上,第三个点在另外一条水平线,这种情况很简单。还有一种情况是三个点在三条水平线上,这时候就可能有不合条件的情况了,我们只需要用总的减掉不符合的就行了,不符合的怎么求? 我们先考虑一下什么情况下不符合条件的,假设选的三个点分别是(r0,c0),(r1,c1),(r2,c2) 不妨设r0 < r1 < r2, 那么当 (r1-r0) / (c1-c0) == (r2-r1) / (c2-c1) 时,在一条直线上,我们可以枚举r1-r0和r2-r1的值,那么就有 a * x == b * y这样的形式, 假设a' = a / gcd(a,b), b' = b / gcd(a,b) , 那么(x,y) 解的形式是这样的 (k * b',k * a') (0<=k<=m/(a'+b')) , 所以我们能够得出三个点的横坐标的差,纵坐标的差,这里随便统计一下就好了
代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <string.h>
#include <cstring>
#include <stdio.h>
#include <cmath>
#include <math.h>
#define rep(i,a,b) for(int i=(a);i<(b);++i)
#define rrep(i,b,a) for(int i = (b); i >= (a); --i)
#define clr(a,x) memset(a,(x),sizeof(a))
#define LL long long
#define eps 1e-10
using namespace std;
const int maxn = 300 + 5;
int gcd(int a,int b)
{
while (a && b) {
if (a > b) a %= b;
else b %= a;
}
return a + b;
}
LL C(LL n,LL m)
{
if (m > n) return 0;
LL ans = 1;
for(LL i = n; i >= n-m+1;--i) {
ans *= i;
}
rep(i,2,m+1) ans /= i;
return ans;
}
int BruteForce(int n,int m)
{
int cnt = 0;
rep(i,0,n*m) rep(j,i+1,n*m) rep(k,j+1,n*m) {
int r0 = i / m, c0 = i % m;
int r1 = j / m, c1 = j % m;
int r2 = k / m, c2 = k % m;
int ok = 1;
if (r0 == r1 && r1 == r2) ok = 0;
if (c1 == c2 && c0 == c1) ok = 0;
if ((r1-r0) * (c2-c1) == (r2-r1) * (c1-c0)) ok = 0;
cnt += ok;
}
return cnt;
}
int main()
{
#ifdef ACM
freopen("in.txt", "r", stdin);
// freopen("out.txt","w",stdout);
#endif // ACM
int n,m;
int cas = 0;
while (scanf("%d%d",&n,&m),n+m) {
++cas;
printf("Case %d: ",cas);
++n; ++m;
if (n > m) swap(n,m);
LL ans = 0;
int g,aa,bb;
rep(a,1,n) rep(b,1,n) {
if (a + b > n) break;
LL amt = m * m * m;
g = gcd(a,b);
LL d = (a+b) / g;
LL k = m / d;
amt -= ((LL)(k+1) * m - (k+1) * k * d / 2) * 2;
amt += m;
ans += amt * (n - a - b);
}
//a * x == b * y
//m - x - y
ans += C(n,2) * (m * C(m,2)) * 2;
printf("%lld\n",ans);
// printf("%d\n",BruteForce(n,m));
}
}