UVA 12075 Counting Triangles

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:

\epsfbox{p3295.eps}

Input 

The input file contains at most 21 sets of inputs.

Each set of input consists of two integers M and N ( 0 < MN$ \le$1000 ). 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));
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值