三角形

题目描述

小 J 是一名 OI 退役滚粗文化课选手, 他十分喜欢做题, 尤其是裸题. 下面就送大家一道裸题. 给定一张 \(N \times M\) 的网格, 计算三个点都在网格上的三角形有多少个. 三角形三点不 能共线.

输入格式

一行两个正整数 N, M.

输出格式

一行一个整数代表数量.

样例输入

1 1

样例输出

4

数据范围

对于 10% 的数据有 \(N, M \leq 10\)

对于 30% 的数据有 \(N, M \leq 100\)

对于 100% 的数据有 \(N, M \leq 1000\)

Explanation

枚举所有的直线斜率, 并不考虑斜率的 \(x\)\(y\) 互质的情况. 进而, 这个操作的时间复杂度明显是 \(O(n m)\) 的.

在这个过程之后, 我们可以得知将一条线段可以拆成几种情况. 这几个拆的位置必须在格点 上. 所以拆的位置只有 \(gcd(n, m)\) 种.

然而总的复杂度的确是 \(O(n m)\) 的.

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>

using namespace std;
typedef long long lli;

lli gcd(lli a, lli b)
{
    while (b != 0) {
        lli c = a % b;
        a = b;
        b = c;
    }
    return a;
}

lli n, m;

int main(int argc, char** argv)
{
    scanf("%lld%lld", &n, &m);
    n++, m++;
    lli tot = (n * m) * (n * m - 1) * (n * m - 2) / 6;
    for (lli i = 1; i <= n; i++)
        for (lli j = 1; j <= m; j++) {
            lli g = 1;
            lli tmp;
            if (i == 1) {
                g = j - 1;
                if (g <= 1)
                    continue;
                tmp = g - 1;
                tmp *= n * (m + 1 - j);
                tot -= tmp;
            } else if (j == 1) {
                g = i - 1;
                if (g <= 1)
                    continue;
                tmp = g - 1;
                tmp *= m * (n + 1 - i);
                tot -= tmp;
            } else {
                g = gcd(i - 1, j - 1);
                if (g <= 1)
                    continue;
                tmp = g - 1;
                tmp *= (n + 1 - i) * (m + 1 - j);
                tmp *= 2;
                tot -= tmp;
            }
            // printf("%d %d %d %d\n", i, j, g, tmp);
        }
    printf("%lld\n", tot);
    return 0;
}