题目描述
给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。
注意:三角形的三点不能共线。n×m的网格共有(n+1)×(m+1)个格点。
输入
输入一行,包含两个空格分隔的正整数m和n(1<=m,n<=1000)。
输出
输出一个正整数,为所求三角形数量。
样例输入
2 2
样例输出
76
容斥原理,先算所有格子中任意取3点的数量,减去三点共线的数量
有n*m个格子,那么就有(n+1)*(m+1)个交点
于是对于所有(n+1)(m+1)=x个交点任意取三点作为三角形三点即x(x-1)*(x-2)/1*2*3【组合数】
组合数C(3,x),从x个点中任意取三个作为三角形三点
首先计算所有点取3点的数量,组合数求,接着减去同在一行和一列的所有情况,那么就是n+1长度的一列上有C(3,K)的种类,总共有m+1列这样的长度,同样m+1长度的n+1行也是一样
除去横向和纵向,接下来是斜着的重复数量,首先从源点0,0开始以不同斜率连接除边界外的每一个点,求GCD(i,j)-1得到在0,0和i,j之间有多少可选点构成三点一线
此处以0,0作为源点,i,j作为一个小的矩形范围内出现重复的区域,以i,j为另一定点,取两定点中间多个动点作为第三个点,有gcd(i,j)-1的匹配数量三点一线
算出以左上角矩形为基点的所有斜向共线可能后,以当前i,j小矩形为一范围,向下平移(n+1-i)个单位得到不同种数,向右平移(m+1-j)个单位得到同样大小的矩形在其他基点的种数
相乘后得到该大小矩形在所有区域的不重复共线可能,然后*2,表示左斜和右斜两种情况
减去所有共线可能后得到最终结果
#include<stdio.h>
#include<string.h>
long long sum(long long x)
{
return x*(x-1)*(x-2)/6;
}
long long gcd(int x,int y)///GCD写错了一直查不到错
{
while(y!=0)
{
long long c=y;
y=x%y;
x=c;
}
return x;
}
int main()
{
long long n,m;///输入n*m个格子,其中有n+1行,m+1列
while(scanf("%lld%lld",&n,&m)!=EOF)
{
long long ans=sum((n+1)*(m+1))-(m+1)*sum(n+1)-(n+1)*sum(m+1);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)///逐个减去不会重复或少减
{
ans-=2*(gcd(i,j)-1)*(m+1-j)*(n+1-i);
}
}
printf("%lld
",ans);
}
}