题目描述

给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。注意三角形的三点不能共线。

输入格式

输入一行,包含两个空格分隔的正整数m和n。

输出格式

输出一个正整数,为所求三角形数量。

输入输出样例

输入 #1
2 2
输出 #1
76

说明/提示

数据范围 1<=m,n<=1000

题解

首先,选三个点的方案是C((n+1)*(m+1),3)

然后减去三点共线的方案数即可

在一行共线的方案数为C(n+1,3)*(m+1)//m+1列

在一列共线的方案数为C(m+1,3)*(n+1)//n+1行

考虑在一条斜线上共线

假设左下方的点到右上方的点的向量为(i,j)

那么,他中间有gcd(i,j)-1个格点

而在(n+1)*(m+1)的图里可以放(n+1-i)*(m+1-j)个这样的向量

而它也有可能是从坐上到右下,方案数一模一样

所以要求的就是∑(i=1)(n)∑(j=1)(m)[ (n+1-i)*(m+1-j)*(gcd(i,j)-1)*2]

为什么我会如此zz地枚举斜线的斜率。。。枚举两个点找第三个点就好了。。。我整个人都傻了

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 long long n,m;
 5 inline long long C(long long x) {if(x<3) return 0;return x*(x-1)*(x-2)/6;}
 6 inline long long gcd(long long x,long long y) {if(y==0) return x; return gcd(y,x%y);}
 7 int main()
 8  {
 9   scanf("%lld%lld",&n,&m); long long ans=C((n+1)*(m+1))-(m+1)*C(n+1)-(n+1)*C(m+1);
10
11   for(long long i=1;i<=n;i++)
12    for(long long j=1;j<=m;j++)
13         ans-=(n+1-i)*(m+1-j)*(gcd(i,j)-1)*2;
14
15
16   printf("%lld",ans);
17  return 0;
18  }
02-13 07:06