• bzoj3505 / P3166 [CQOI2014]数三角形


    P3166 [CQOI2014]数三角形

    前置知识:某两个点$(x_{1},,y_{1}),(x_{2},y_{2})quad (x_{1}<x_{2},y_{1}<y_{2})$所连成的线段穿过整点的个数为$gcd(x_{2}-x_{1},y_{2}-y_{1})-1$

    “注意三角形的三点不能共线。”

    暗示你可以处理出总方案再减去三点共线的方案。

    显然,总方案就是在$(n+1)*(m+1)$个点中任选$3$个。于是$tot=C((n+1)*(m+1),3)$

    现在我们要算出三点共线的方案

    对于直线上的三点共线,显然$tot1=n*C(m,3)+m*C(n,3)$

    对于斜线上的三点共线,我们可以根据前置知识↑↑枚举。

    然鹅暴力枚举复杂度是达到$O(n^{2}m^{2})$的

    所以我们需要转化

    注意到其实我们可以只枚举$l=x_{2}-x_{1},r=y_{2}-y_{1}$,相当于把这两个数据看做一个矩形的长和宽。

    蓝后我们要算出整个大矩形中有几个这样的小矩形:$(n-l+1)*(m-r+1)$

    每个矩形中包含$2$条对角线,所以$tot2*=2$

    所以斜线上的三点共线$tot2=sum_{i=1}^{n}sum_{j=1}^{m}(gcd(i,j)-1)*(n-i+1)*(m-j+1)$

    代码中为了方便事先把$n,m$都$+1$

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #define re register
     5 using namespace std;
     6 typedef long long ll;
     7 ll m,n,ans;
     8 int gcd(int a,int b){return b?gcd(b,a%b):a;}
     9 int main(){
    10     scanf("%lld%lld",&n,&m);++n;++m;
    11     ll tmp=n*m;
    12     ans=tmp*(tmp-1)*(tmp-2)/6;
    13     ans-=n*m*(m-1)*(m-2)/6;
    14     ans-=m*n*(n-1)*(n-2)/6;//减去横向和纵向的三点共线
    15     for(int i=1;i<n;++i)
    16         for(int j=1;j<m;++j)
    17             ans-=1ll*(gcd(i,j)-1)*(n-i)*(m-j)*2;
    18     printf("%lld",ans);
    19     return 0;
    20     return 0;
    21 }
    View Code
  • 相关阅读:
    java 模块调用
    JAVA 方法引用
    JAVA 接口中静态方法
    JAVA 反射获取class类对象
    JAVA 引用对象的实例方法
    JAVA Lambda表达式的使用
    JAVA 接口中默认方法
    JAVA中Function的使用
    JAVA TCP客户端读区文件,服务端写入文件
    JAVA 反射练习
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9906533.html
Copyright © 2020-2023  润新知