博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[bzoj3505][CQOI2014]数三角形_组合数学
阅读量:5074 次
发布时间:2019-06-12

本文共 1107 字,大约阅读时间需要 3 分钟。

数三角形 bzoj-3505 CQOI-2014

题目大意:给你一个n*m的网格图,问你从中选取三个点,能构成三角形的个数。

注释:$1\le n,m\le 1000$。

想法:本来是想着等中考完了之后花上一周的时间把之前欠的blog都更掉,然后做了这道题发现网上的题解让我匪夷所思(他们写着任何人都能看懂的代码,说着只有自己才能听懂的话)。其实是这样的,求三角形个数就等价于求有多少种选取的方案使得点共线。显然竖着的和横着的都是可以O(1)的,我们只需要计算着的就行了。那么,我们枚举什么才能使得在O(能过)的情况下出解?我们对于一个网格图(0,0)到(a,b),对角线上的点显然可以用gcd来求。我们已经知道了对角线上的点,然后算一下这些点所有的三点共线的方案数?算完了之后发现后面没法进行了,所以对于每一个这样的矩形我们不能直接计算。我们对于每一个a*b的网格矩形只计算这样的三点共线:这三个共线的点中外边两个点之间线段是我们枚举网格矩阵的对角线。换言之,我们对于一个已经求好了对角线上有多少整点的方格矩形,它对答案的共线就是gcd。这样计算是不会重复的,对于每一种三点共线的选取方案,只会在端点是当前枚举矩形的对角线端点是才会被计算,所以这样是不重不漏的。我们这样枚举贴在(0,0)上的矩形,紧接着算一下整个n*m的方格图里有多少这样的矩形,然后直接累计答案即可。总时间复杂度O(n*n*(gcd的log))。

最后,附上丑陋的代码... ...

#include 
#include
#include
#include
using namespace std;typedef long long ll;int n,m;ll ans;ll C(int x){ return (ll)x*(x-1)*(x-2)/6;}int main(){ scanf("%d%d",&n,&m); n++;m++; ans=C(n*m)-(ll)n*C(m)-(ll)m*C(n); for (int i=1;i
=1) ans-=(ll)(n-i)*(m-j)*num*2; } printf("%lld\n",ans); return 0;}

小结:好题。枚举的方式决定了解决问题的难易程度。

转载于:https://www.cnblogs.com/ShuraK/p/9113173.html

你可能感兴趣的文章
批处理 windows 服务的安装与卸载
查看>>
React文档翻译 (快速入门)
查看>>
nodejs fs路径
查看>>
动态规划算法之最大子段和
查看>>
linux c:关联变量的双for循环
查看>>
深入浅出理解zend framework(三)
查看>>
python语句----->if语句,while语句,for循环
查看>>
javascript之数组操作
查看>>
LinkedList源码分析
查看>>
TF-IDF原理
查看>>
用JS制作博客页面背景随滚动渐变的效果
查看>>
JavaScript的迭代函数与迭代函数的实现
查看>>
一步步教你学会browserify
查看>>
Jmeter入门实例
查看>>
亲近用户—回归本质
查看>>
中文脏话识别的解决方案
查看>>
CSS之不常用但重要的样式总结
查看>>
Python编译错误总结
查看>>
URL编码与解码
查看>>
日常开发时遇到的一些坑(三)
查看>>