[CQOI2014] 数三角形

Description

给定一个 n×mn\times m 的网格,计算三个点都在格点上的三角形共有多少个。三角形的三点不能共线。
n,m103n,m\leq 10^3

Solution

记这个题在这里就是为了记一句话:
「枚举两个顶点是四次方的。但实际上我们大多数时候并不在意两个顶点的具体坐标,而只关心两点的相对坐标差。枚举横纵坐标差就是平方的,极大优化了复杂度。」
一直就觉得枚举两个顶点这样一个简单的操作居然是 4\sout{4} 次方极其不便

然后这个题就很简单了。枚举横坐标差/纵坐标差,那么斜线上的三点共线数量为

i=1nj=1m(ni)(mi)(gcd(i,j)1)\sum_{i=1}^{n}\sum_{j=1}^{m}(n-i)(m-i)(\gcd(i,j)-1)

总方案减去就行了。

然后也可以用数论函数的知识,将后面的 gcd\gcd 拆成欧拉函数的形式。可以做到 O(n)\mathcal{O}(n)

Code

#include <bits/stdc++.h>
using namespace std;
long long n, m;
int gcd(int a, int b){
    return !b ? a : gcd(b, a % b);
}
int main(){

    cin >> n >> m; 
    ++n, ++m;
    long long ans = n * m * (n * m - 1) * (n * m - 2) / 6;
    ans -= m * n * (n - 1) * (n - 2) / 6;
    ans -= 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;
}