一个三角形由三个不共线的点组成,也就是说,三角形的个数等于三点不共线的组数。由于三点不共线的组数比较难算,可以通过计算它的补集三点共线的组数,再由总数C(n*m,3)减去。
计算方法和Highway比较类似,若已知n行m列的答案,新增第n+1行,令n+1行的第一个点为a,那么a所在的三点共线满足什么条件?有多少组?
几何上三点共线任意两点斜率相等,如果再加上各坐标值是整数这个限制条件,那么可得,最低点与最高点的横坐标之差与纵坐标之差非互质,即最大公约数K大于1。组数为K-1。我们可以枚举一个与a非同行同列的b,计算a与b连线上的三点共线组数。
但是,跟上一题Highway一样,要考虑重复计算的问题。在枚举时,我们是假设b是最高点,实际上,在a与b的延长线可能存在一点更高点c,这时我们减去重复值。
后来在写解题报告的时候,忽然想到直接计算以a为最低点和b为最高点的三点共线组数,这样就不用减去重复值了,思路更为清晰。(受了Highway思路的影响)
1 #include <cstdio> 2 #include <cstring> 3 #define LL long long 4 using namespace std; 5 6 const int maxn = 1010; 7 LL f[maxn][maxn]; 8 9 int gcd(int a, int b) 10 { 11 return b ? gcd(b, a % b) : a; 12 } 13 14 LL C(LL n) 15 { 16 return n * (n - 1) * (n - 2) / 6; 17 } 18 19 void init() 20 { 21 int i, n, j, k; 22 memset(f, 0, sizeof(f)); 23 n = 1000; 24 for(i = 2; i <= n; i ++) 25 for(j = 2; j <= n; j ++) 26 f[i][j] = (LL)(gcd(i, j) - 1); 27 28 for(i = 2; i <= n; i ++) 29 for(j = 3; j <= n; j ++) 30 f[i][j] += f[i][j - 1]; 31 32 for(i = 3; i <= n; i ++) 33 for(j = 2; j <= n; j ++) 34 f[i][j] += f[i - 1][j]; 35 } 36 37 int main() 38 { 39 int i, n, j, m, kase; 40 init(); 41 for(kase = 1;scanf("%d%d", &n, &m), n + m; kase ++) 42 { 43 n ++, m ++; 44 LL ans = C(n * m) - n * C(m) - m * C(n); 45 for(i = 2; i < n; i ++) 46 for(j = 0; j < m; j ++) 47 ans -= f[i][m - 1 - j] + f[i][j]; 48 printf("Case %d: %lld ", kase, ans); 49 } 50 return 0; 51 }