### 题目意思
数三角形的数量
### 思路
这道题一眼看去有一个非常显然的想法,那就是先用组合数算出任选三点出来的方案数,最后再减去三点共线的情况即可。那么关键就在于如何求三点共线的数目。
我们要用到一个公式:设两个整点分别为$$(x1,y1)$$,$$(x2,y2)$$,那么两点之间连线上的整点数目为 $$gcd(|x1-x2|,|y1-y2|)$$
接下来我们对直线在x轴 ,y 轴的射影长度进行枚举。
__横着竖着,算一次,斜着的算两次(分别是:左上到右下 或 右上到左下)__
``` cpp
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
using namespace std;
typedef long long int LL;
int gcd(int a,int b)
{
return __gcd(a,b);
}
LL getnum(int x,int y)
{
LL res=0;
if(x==0&&y==0) return 0;
else if(x==0) return y-1;
else if(y==0) return x-1;
return (gcd(x,y)-1)*2;
}
int main(int argc, char const *argv[])
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
//printf("n=%d m=%d\n",n,m);
LL tot=(n+1ll)*(m+1ll);
LL ans=tot*(tot-1)*(tot-2)/6;
//printf("tot=%d\n",tot);
//printf("%lld\n",ans);
for(int i=0;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
LL num1=1ll*(n-i+1)*(m-j+1);
LL num2=getnum(i,j);
LL tmp=num2*num1;
ans-=tmp;
// printf("i=%d j=%d tmp=%lld\n",i,j,tmp);
}
}
printf("%lld\n",ans);
}
return 0;
}
```
数三角形的数量
### 思路
这道题一眼看去有一个非常显然的想法,那就是先用组合数算出任选三点出来的方案数,最后再减去三点共线的情况即可。那么关键就在于如何求三点共线的数目。
我们要用到一个公式:设两个整点分别为$$(x1,y1)$$,$$(x2,y2)$$,那么两点之间连线上的整点数目为 $$gcd(|x1-x2|,|y1-y2|)$$
接下来我们对直线在x轴 ,y 轴的射影长度进行枚举。
__横着竖着,算一次,斜着的算两次(分别是:左上到右下 或 右上到左下)__
``` cpp
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
using namespace std;
typedef long long int LL;
int gcd(int a,int b)
{
return __gcd(a,b);
}
LL getnum(int x,int y)
{
LL res=0;
if(x==0&&y==0) return 0;
else if(x==0) return y-1;
else if(y==0) return x-1;
return (gcd(x,y)-1)*2;
}
int main(int argc, char const *argv[])
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
//printf("n=%d m=%d\n",n,m);
LL tot=(n+1ll)*(m+1ll);
LL ans=tot*(tot-1)*(tot-2)/6;
//printf("tot=%d\n",tot);
//printf("%lld\n",ans);
for(int i=0;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
LL num1=1ll*(n-i+1)*(m-j+1);
LL num2=getnum(i,j);
LL tmp=num2*num1;
ans-=tmp;
// printf("i=%d j=%d tmp=%lld\n",i,j,tmp);
}
}
printf("%lld\n",ans);
}
return 0;
}
```