UPC-3843 数三角形(容斥原理+gcd+组合数)

题目描述
给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。
这里写图片描述

注意:三角形的三点不能共线。n×m的网格共有(n+1)×(m+1)个格点。
输入
输入一行,包含两个空格分隔的正整数m和n(1<=m,n<=1000)。
输出
输出一个正整数,为所求三角形数量。
样例输入
2 2
样例输出
76

容斥原理,先算所有格子中任意取3点的数量,减去三点共线的数量
有n*m个格子,那么就有(n+1)*(m+1)个交点
于是对于所有(n+1)(m+1)=x个交点任意取三点作为三角形三点即x(x-1)*(x-2)/1*2*3【组合数】
组合数C(3,x),从x个点中任意取三个作为三角形三点
首先计算所有点取3点的数量,组合数求,接着减去同在一行和一列的所有情况,那么就是n+1长度的一列上有C(3,K)的种类,总共有m+1列这样的长度,同样m+1长度的n+1行也是一样

除去横向和纵向,接下来是斜着的重复数量,首先从源点0,0开始以不同斜率连接除边界外的每一个点,求GCD(i,j)-1得到在0,0和i,j之间有多少可选点构成三点一线

此处以0,0作为源点,i,j作为一个小的矩形范围内出现重复的区域,以i,j为另一定点,取两定点中间多个动点作为第三个点,有gcd(i,j)-1的匹配数量三点一线

算出以左上角矩形为基点的所有斜向共线可能后,以当前i,j小矩形为一范围,向下平移(n+1-i)个单位得到不同种数,向右平移(m+1-j)个单位得到同样大小的矩形在其他基点的种数

相乘后得到该大小矩形在所有区域的不重复共线可能,然后*2,表示左斜和右斜两种情况

减去所有共线可能后得到最终结果

#include<stdio.h>
#include<string.h>
long long sum(long long x)
{
    return x*(x-1)*(x-2)/6;
}
long long gcd(int x,int y)///GCD写错了一直查不到错
{
    while(y!=0)
    {
        long long c=y;
        y=x%y;
        x=c;
    }
    return x;
}
int main()
{
    long long n,m;///输入n*m个格子,其中有n+1行,m+1列
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        long long ans=sum((n+1)*(m+1))-(m+1)*sum(n+1)-(n+1)*sum(m+1);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)///逐个减去不会重复或少减
            {
                ans-=2*(gcd(i,j)-1)*(m+1-j)*(n+1-i);
            }
        }
        printf("%lld\n",ans);
    }
}
posted @ 2018-03-18 00:33  KuroNekonano  阅读(170)  评论(0编辑  收藏  举报