UVa 12075 / LA 3295 Counting Triangles

    一个三角形由三个不共线的点组成,也就是说,三角形的个数等于三点不共线的组数。由于三点不共线的组数比较难算,可以通过计算它的补集三点共线的组数,再由总数C(n*m,3)减去。

计算方法和Highway比较类似,若已知nm列的答案,新增第n+1行,令n+1行的第一个点为a,那么a所在的三点共线满足什么条件?有多少组?

 

几何上三点共线任意两点斜率相等,如果再加上各坐标值是整数这个限制条件,那么可得,最低点与最高点的横坐标之差与纵坐标之差非互质,即最大公约数K大于1。组数为K-1。我们可以枚举一个与a非同行同列的b,计算ab连线上的三点共线组数。

但是,跟上一题Highway一样,要考虑重复计算的问题。在枚举时,我们是假设b是最高点,实际上,在ab的延长线可能存在一点更高点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 }
原文地址:https://www.cnblogs.com/xchaos/p/3293463.html