• 「题解」:数三角形


    考拉学长杂题选讲最(水?)的一道题。

    题面


    题目描述

    给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。注意三角形的三点不能共线。

    样例输入

    2 2

    样例输出

    76

    题解


    直接求不现实。所以一点点容斥?

    我们先求出来在全部的$t$个点$((n+1)*(m+1))$中任意选三个点的全部组合

    $frac{(t-2)*(t-1)*t}{3!}$ (解释:从t个数里选出第一个,剩下t-1个数中选第二个,t-2个数里选第三个,除以三个数的内部排列数)

    然后我们尝试减去不合法的选择:

    <1>.单行、单列上不合法的数量:与之前一样,只不过要在单行或者单列上选择。在单行上$frac{(m+1)*m*(m-1)}{3!}$,推广到每一行,乘以行数,即为:$frac{(m+1)*m*(m-1)}{3!}*(n+1)$,同理,在单列上为$frac{(n+1)*n*(n-1)}{3!}$,推广到每一列,乘以列数,即为:$frac{(n+1)*n*(n-1)}{3!}*(m+1)$。

    <2>.斜着共线的三点的情况数量:设1点的坐标为$(x_1,y_1)$、$(x_2,y_2)$,则$gcd(x_1-x_2,y_1-y_2)-1$恰为点阵中1点和2点之间点的数量。一个非常显然的性质是:我们求出了一个斜线完全可以在点阵上平移,对称翻折。于是我们考虑优化:把其中一个点固定在左上角,然后枚举图中点的坐标,最后得出,左上角与枚举的端点相连所得的直线平移的可能总数为:$(n-x+1)*(m-y+1)$。于是得出公式:$(n-i+1)*(m-j+1)*2*(gcd(i,j)-1)$,两层for循环枚举i,j作为节点横纵坐标即可。

    代码:

    #include<iostream>
    #include<cstdio>
    #define rint register int
    using namespace std;
    long long n,m,t;
    long long ans=0,row,line,inc;
    inline int gcd(long long a,long long b)
    {
        return b==0?a:gcd(b,a%b);
    }
    int main()
    {
        scanf("%lld %lld",&m,&n);
        t=(m+1)*(n+1);
        ans=t*(t-1)*(t-2)/6;
        row=(n+1)*(m+1)*m*(m-1)/6;line=(m+1)*(n+1)*n*(n-1)/6;
        for(rint i=1;i<=n;++i)
            for(rint j=1;j<=m;++j)
                inc+=(n-i+1)*(m-j+1)*2*(gcd(i,j)-1);
        ans-=row;ans-=line;ans-=inc;
        cout<<ans<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    python--模块
    python--*args与**kw
    python--偏函数
    Reversible Cards ARC111 -B 思维,图论
    Simple Math ARC111
    状压DP详解(位运算)
    E
    Ball CodeForces
    Reward HDU
    Choosing Capital for Treeland CodeForces
  • 原文地址:https://www.cnblogs.com/xingmi-weiyouni/p/11230899.html
Copyright © 2020-2023  润新知