题目链接
题意
求在网格上,三点都在格点上的三角形个数。
思路
看到题面,觉得正着想有点难,考虑用整体减去不满足的就是答案。
在网格里选三个点,方案数是 C ( n + 1 ) ( m + 1 ) 3 \text{C}_{(n+1)(m+1)}^{3} C(n+1)(m+1)3。
三点共线的情况还可以分成三种:
1. 1. 1. 横着三点共线。
2. 2. 2. 竖着三点共线。
3. 3. 3. 斜着三点共线。
前两种都可以直接考虑,以第一种为例,在 n + 1 n+1 n+1 行里选三个点,有 m + 1 m+1 m+1 列,所以方案数是 C n + 1 3 × ( m + 1 ) \text{C}_{n+1}^{3} \times (m+1) Cn+13×(m+1) 种。第二种同理,方案数是 C m + 1 3 × ( n + 1 ) \text{C}_{m+1}^{3} \times (n+1) Cm+13×(n+1) 种。
考虑第三种,先选择两点 ( 0 , 0 ) (0,0) (0,0) 以及 ( i , j ) (i,j) (i,j),这条直线解析式为 y = j i x y=\frac{j}{i}x y=ijx。要想坐标为整数,就要 j j j 能整除 i i i,所以 j j j 与 i i i 互质时肯定不行。
设 g c d ( i , j ) = d gcd(i,j)=d gcd(i,j)=d,那么解析式变为 y = j / d i / d x y=\frac{j/d}{i/d}x y=i/dj/dx。那么只要 i / d ∣ x i/d|x i/d∣x 就可以了。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
inline int read(){
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int maxn=1e3+5;
int n,m,x,y,ans;
signed main(){
x=read(),y=read(),n=x+1,m=y+1;
ans=(n*m)*(n*m-1)*(n*m-2)/6-m*n*(n-1)*(n-2)/6-n*m*(m-1)*(m-2)/6;
for(int i=1;i<n;i++) for(int j=1;j<m;j++) ans-=2*(__gcd(i,j)-1)*(n-i)*(m-j);
cout<<ans<<endl;
return 0;
}