CQOI2014 数三角形

题目

Luogu P3166

给定正整数 \(N,M\) ,计算三点都在 \(N\times M\) 的网格的格点上的三角形有多少个

分析

可以发现,只要三点位于格点且不共线就能形成三角形,考虑计算三点共线的情况:

  • 平行于 \(x\) 轴共线:

    每行有 \(m+1\) 个点,共 \(n+1\) 行,所以有 \((n+1)\times\displaystyle\binom{m+1}{3}\) 种情况

  • 平行于 \(y\) 轴共线:

    每列有 \(n+1\) 个点,共 \(m+1\) 列,所以有 \((m+1)\times\displaystyle\binom{n+1}{3}\) 种情况

  • \(x,y\) 轴都不平行的共线:

    \(AB\) 平行于 \(x\) 轴且 \(|AB|=i\)\(AC\) 平行于 \(y\) 轴且 \(|AC|=j\) ,共线的三点中 \(B,C\) 为两个端点,那么 \(B,C\) 之间的格点数为 \(\gcd(i,j)+1\) ,所以共线的第三点有 \(\gcd(i,j)-1\) 种情况,易知形成 \(AB,AC\) 的有 \((n+1-i)\times(m+1-j)\) ,所以斜共线的总情况数为:

    \[2\sum_{i=1}^n\sum_{j=1}^m (n+1-i)(m+1-j)[\gcd(i,j)-1] \]

综上,算出总和 \(\displaystyle\binom{(n+1)(m+1)}{3}\) 再减去上述三种反面情况即可

代码

#include<bits/stdc++.h>
using namespace std;

int gcd(int a, int b)
{
    return a % b == 0 ? b : gcd(b, a % b);
}

int main()
{
    int n, m;
    long long ans;
    cin >> n >> m;
    n++;
    m++;
    ans = 1ll * (n * m) * (n * m - 1) * (n * m - 2) / 6;
    ans -= 1ll * m * n * (n - 1) * (n - 2) / 6;
    ans -= 1ll * n * m * (m - 1) * (m - 2) / 6;
    for(int i = 1; i < n; i++)
        for(int j = 1; j < m; j++)
            ans -= 2ll * (n - i) * (m - j) * (gcd(i, j) - 1);
    cout << ans << endl;
    return 0;
}
posted @ 2021-12-21 16:49  f(k(t))  阅读(35)  评论(0编辑  收藏  举报