BZOJ3505 数三角形 题解 【数论】

来源:互联网 发布:c 数据采集系统源代码 编辑:程序博客网 时间:2024/06/05 08:39

【题目描述】
给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。
(这里真的没有图片)
注意三角形的三点不能共线。
【题解】
这道题的题目实质上就给了我们一个提示:三点共线的点。我们只需要找出所有的点的组合(排列组合),再减去这其中共线的就行了。共线的点有三类:同行,同列,同斜线(判断gcd)
为了解决同斜线的情况,我们打一个gcd的表,再用这个表算术就行了。
代码如下:

#include<cstdio>#define LL long longint gcd[1010][1010];int n,m;LL t,ans;inline int getgcd(int a,int b){    if(gcd[a][b])return gcd[a][b];    if(!a)return gcd[a][b]=b;    if(!b)return gcd[a][b]=a;    return gcd[a][b]=getgcd(b,a%b);}inline void calc()//打表算出两数的gcd {    for(int i=1;i<=m;i++)gcd[0][i]=i;    for(int i=1;i<=n;i++)gcd[i][0]=i;    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)    getgcd(i,j);}int main(){    scanf("%d%d",&n,&m);    calc();    t=(n+1)*(m+1);    ans=t*(t-1)*(t-2)/6;//从这么多点里面选三个的全部情况     for(int i=0;i<=n;i++)    for(int j=0;j<=m;j++)    if(i||j)//减去三点共线的情况     {        if(!i||!j)ans-=(LL)(gcd[i][j]-1)*(n-i+1)*(m-j+1);        else ans-=(LL)2*(gcd[i][j]-1)*(n-i+1)*(m-j+1);    }    printf("%lld",ans);    return 0;}
原创粉丝点击