P3166 数三角形
题目简述
给定一个
思路
直接求三角形的个数比较困难。我们知道在网格中随便选三个不共线的格点就可以构成一个三角形,所以总选法减去三点共线的方案数就是三角形的个数。
横纵向三点共线的方案很好统计:对于题目中
接下来我们考虑一下斜向三点共线的方案数:选定三点中的两个点作为一条线段上的两个端点,线段上(除两端点)的格点数就是在两点确定的情况下三点共线的方案数。
不妨看一下这张图:黑色的线是我们选定两端点构成的线段,添加灰色的辅助线我们可以以它为斜边扩展成一个两条直角边分别为
刚才只是对于一个固定的线段分析的,同样形态的线段可以在网格中的多个位置出现,线段也会有不同的形态。我们可以枚举
值得注意的是,
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<climits>
#include<utility>
#define int long long
using namespace std;
int n, m, ans;
inline int GCD(int a, int b){
return b>0 ? GCD(b, a%b) : a;
}
signed main(){
scanf("%lld%lld", &n, &m);
n++, m++;
ans = (n*m)*(n*m-1)*(n*m-2)/6;
if(n >= 3) ans -= (n*(n-1)*(n-2)/6) * m;
if(m >= 3) ans -= (m*(m-1)*(m-2)/6) * n;
for(int i=1;i<n;i++)
for(int j=1;j<m;j++){
ans -= (n-i)*(m-j)*(GCD(i,j)-1)*2;
}
printf("%lld", ans);
return 0;
}