Gao the Grid ZOJ 3647 数三角形
首先从所有的点中选3个点用来画三角形,一共有ans = C((n+1)*(m+1),3)种,然后减去三点共线的情况,三点水平和垂直共线很好考虑,ans -= (n+1)*C(m+1,3)
ans -= (m+1)*C(n+1,3).
然后针对斜线的情况,用枚举法。
先考虑如下的情况:
假设有一条过原点(0,0)和点(x0,y0)的线段,其中x0,y0均为正整数,那么这条线段上有多少个整数点呢。整数点就是坐标为(x,y)的点,其中x,y均为整数 。
答案上gcd(x0,y0)+1,下面证明:
这条线段的方程如下:y = k * x ,其中k = y0/x0. (x>=0 && x <= x0)
那么设y0分解为y0 = p1 * p2 ```` pk
x0的分解为x0 = q1*q2*q3````qs其中pi,qi均为素数
不妨设p1= q1,p2=q2,```pt =qt.剩下的pi和qj互素(i=t+1,```k,j=t+1,s),显然,p1*p1*```*pt就是gcd(x0,y0)(也就是x0 和 y0 的最大公约数)。
那么y = k *x,当x取值为q(t+1)*q(t+2)*```*q(s),也就是x0/gcd(x0,y0)时,y为小于y0的整数,令d = x0/gcd(x0,y0),x取值为0*d,1*d,2*d ,```` gcd(x0,y0)*d,y都会是>=0,<=y0的整数,而这样选择的x也是>=0,<=x0的整数,所有在这条线段上一共有gcd(x0,y0)个整数点。由此得证。
这样的话,选定两个整数点(两整数点不在同一水平线或垂直线上,只考虑斜线的情况),再在这两个点组成的线段上另选一个点和这个点组成伪三角形,这样的伪三角形有多少个。
答案是,自己好好想想,呵呵,然后先列举斜率为正的斜线,然后发现斜率为负的斜率与之对称,所以斜率为正的斜线的伪三角形的个数*2即可
贴代码:
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 typedef long long LL; 5 int gcd(int a,int b) 6 { 7 return b==0 ? a : gcd(b,a%b); 8 } 9 LL pc3(LL x) 10 { 11 LL y; 12 y = x*(x-1)*(x-2)/6; 13 return y; 14 } 15 int main() 16 { 17 int n,m; 18 while(~scanf("%d%d",&n,&m)) 19 { 20 LL ans = pc3((n+1)*(m+1)); 21 ans -= (m+1)*pc3(n+1); 22 ans -= (n+1)*pc3(m+1); 23 for(int i=2; i<=n; ++i) 24 { 25 for(int j=2; j<=m; ++j) 26 { 27 ans -= (long long int )(gcd(i,j)-1)*(n+1-i)*(m+1-j)*2; 28 } 29 } 30 cout<<ans<<endl; 31 } 32 return 0; 33 }