题目大意:给一张m*n的网格,问这里面以网格为顶点的三角形有多少个
题解:坐标从0开始,所以有(n+1)*(m+1)个点,输入后n++,m++
不考虑共线的话是
C3n∗m
,然后需要减去横竖斜三种共线
横竖明显是
n∗C3m
和
m∗C3n
下面考虑斜共线
结论: (0,0) 和 (i,j) 连线上整点的个数为 gcd(i,j)+1 (包括 (0,0) 和 (i,j) )
固定点 (0,0) ,枚举点 (i,j) ,这样就确定了斜率k,只需要统计k为正的即可(负的可以通过翻转,0和不存在已经计算过了),考虑所成线段,中间有 gcd(i,j)−1 个点
乘上(n-i)*(m-j),即通过平移能找到多少条这样的线段
有两种情况:一种是枚举的(0,0)-(i,j),即从左下角->右上角,还有一种(i,0)->(0,j),即从右下角->左上角,这两种情况是相同的,最后要乘2
我的收获:思考方向
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m;
long long ans;
long long C(int x){return (long long)x*(x-1)*(x-2)/6;}
void work()
{
ans=C(n*m)-C(n)*m-C(m)*n;
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
ans-=2ll*(__gcd(i,j)-1)*(n-i)*(m-j);
printf("%lld\n",ans);
}
void init(){
cin>>n>>m;n++;m++;
}
int main()
{
init();
work();
return 0;
}