1. 题目背景与问题分析
在网格中计算不共线的三点组成的三角形数量,这是一个经典的组合数学问题。给定一个N×M的网格,我们需要计算所有可能的三角形组合,同时排除三点共线的情况。
这个问题看似简单,但实际涉及多个数学概念:
- 组合数学中的排列组合
- 欧拉函数(φ函数)的应用
- 最大公约数(GCD)的性质
- 网格几何中的直线斜率分析
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解题思路解析
2.1 总体思路框架
解决这个问题的核心思路可以分解为以下几步:
- 计算网格中所有可能的三点组合数
- 减去所有三点共线的情况
- 三点共线的情况包括:
- 水平直线上的点
- 垂直直线上的点
- 斜线(各种斜率)上的点
2.2 数学公式推导
总三角形数量 = 所有三点组合 - 共线三点组合
具体公式为:
code复制ans = C((n+1)*(m+1), 3) - (m+1)*C(n+1, 3) - (n+1)*C(m+1, 3) - 斜线共线情况
其中:
- C(n,3)表示从n个点中取3个点的组合数
- (m+1)*C(n+1,3)表示所有垂直方向上的共线三点
- (n+1)*C(m+1,3)表示所有水平方向上的共线三点
2.3 斜线共线情况处理
斜线共线情况是最复杂的部分,需要考虑:
- 不同斜率的直线
- 直线在网格中的位置
- 每条直线上包含的格点数
这里使用了欧拉函数来高效计算斜线情况,具体公式为:
code复制ans += φ(d) * (n-d+n%d+2) * (n/d) * (m-d+m%d+2) * (m/d) / 2
3. 代码实现详解
3.1 欧拉筛法实现
cpp复制void sieve(int n) {
phi[1] = 1;
for(int i = 2; i <= n; ++i) {
if(!mark[i]) p[++tot] = i, phi[i] = i - 1;
for(int j = 1; j <= tot and p[j]*i <= n; ++j) {
mark[p[j]*i] = true;
if(i % p[j]) phi[p[j]*i] = ph
