Description
给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。
注意三角形的三点不能共线。
Sample Input
2 2
Sample Output
76
我们首先可知不管三点一线的答案有C(n,3)种。
然后横着的直线跟竖着的支线很好搞出来。
然后考虑斜着的直线,对于两个点,
设差值为x,y,形成的直线上面会有gcd(x,y)-1个整点,
这个线段能平移的往上范围是n-x+1,往右平移的范围是m-y+1。
那么你还可以反转,于是共有(n-x+1) * (m-y+1) * 2 * (gcd(x,y)-1)种。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
LL f[1100][1100];
LL gcd(LL a, LL b) {
if(b == 0) return a;
return gcd(b, a % b);
}
LL get(LL x) {return x * (x - 1) * (x - 2) / 6;}
int main() {
LL n = read(), m = read(); n++, m++;
LL ans = get(n * m) - (LL)get(n) * m - (LL)get(m) * n;
for(LL i = 1; i < n; i++) {
for(LL j = 1; j < m; j++) {
LL k = gcd(i, j) - 1;
ans -= (LL)k * (n - i) * (m - j) * 2LL;
}
} printf("%lld\n", ans);
return 0;
}