标签:排列组合,数学
Description
给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。
注意三角形的三点不能共线。
Input
输入一行,包含两个空格分隔的正整数m和n。
Output
输出一个正整数,为所求三角形数量。
Sample Input
2 2
Sample Output
76
数据范围
1<=m,n<=1000
我们可以利用补集的思想,用排列组合C(n*m,3)算出总方案数,之后减去一些不符合条件的方案
1. 三点共一条水平直线
2. 三点共一条竖直直线
3. 三点共一条斜线(用gcd判断和计算)
Code
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define rep(i,a,b) for(int i=a;i<=b;i++) #define dep(i,a,b) for(int i=a;i>=b;i--) #define LL long long #define mem(x,num) memset(x,num,sizeof x) using namespace std; inline LL read() { LL f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline int gcd(int a,int b){return b==0?a:gcd(b,a%b);} const int maxn=1e6+6; LL c[maxn][4],n,m,ans,t; int main() { n=read(),m=read(); n++,m++; c[0][0]=1; rep(i,1,n*m){ c[i][0]=1; rep(j,1,3)c[i][j]=c[i-1][j-1]+c[i-1][j]; } ans=c[n*m][3]; ans-=n*c[m][3]; ans-=m*c[n][3]; rep(i,1,n-1) rep(j,1,m-1){ t=gcd(i,j)+1; if(t>2)ans-=(t-2)*2*(n-i)*(m-j); } printf("%lld\n",ans); return 0; }