码迷,mamicode.com
首页 > 其他好文 > 详细

数三角形

时间:2019-06-30 12:30:35      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:ret   amp   div   com   name   优化   思路   cal   alc   

题面

给定一个$n*m$的网格,请计算三点都在格点上的三角形共有多少个。下图为$4*4$的网格上的一个三角形。

技术图片

 

 

 

 

 

 

 

 

 

 

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

思路

三角形总数=随便在点阵上选3个点的方案数-共线方案数

总方案数

设t为总点数,为$(n+1)*(m+1)$,看看图就知道了。

随便选3个点的方案数$\frac{t!}{(t-3)!3!}=\frac{(t-2)\ast(t-1)\ast t}6$

横竖不合法方案

设$calc(x)=\frac{x!}{(x-3)!3!}=\frac{(x-2)\ast(x-1)\ast x}6$

横行为$calc(m+1)*(n+1)$

竖列为$calc(m+1)*(n+1)$

斜线不合法方案

斜线整点(除端点)公式为$gcd(x_1-x_2,y_1-y_2)-1$

前提是$x_1>x_2,y_1>y_2,两点为端点$

然后就是考虑优化了

  1. 显然在点阵中相同斜线可以不用计算,平移即可
  2. 对称斜线乘2即可,也就是说只用考虑单向的斜线

技术图片

 

 

 

 

 

 

 

 

 

如图斜线,蓝色部分的点都是该斜线下面那个端点(2,2)可以移到的(边缘也可以),如果不是则上面的端点(0,0)会超出点阵,所以每个端点的平移方案有$(n-i+1)*(m-j+1)$。

则可枚举右下端点坐标。

把所有的$(n-i+1)*(m-j+1)*2*(gcd(i,j)-1)$相加即可。

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 long long n,m;
 4 long long calc(long long x){return x*(x-1)*(x-2)/6;}
 5 int main()
 6 {
 7     scanf("%lld%lld",&n,&m);
 8     long long t=(n+1)*(m+1);
 9     long long tot=t*(t-1)*(t-2)/6-calc(n+1)*(m+1)-calc(m+1)*(n+1);
10     for (int i=1;i<=n;i++)
11      for (int j=1;j<=m;j++)
12       tot-=(n-i+1)*(m-j+1)*2*(__gcd(i,j)-1);
13     cout<<tot<<endl;
14     return 0;
15 } 

 

数三角形

标签:ret   amp   div   com   name   优化   思路   cal   alc   

原文地址:https://www.cnblogs.com/GaryFang/p/11108693.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!