题目链接:点击查看

题目大意:给出 n ( n <= 2000 ) 个点,求出所有不同的锐角三角形的面积

题目分析:n^3 暴力枚举肯定是不可以的,和之前写过的一个题目思路很像:HDU-5784

所以这个题目的思路就是,枚举所有的角,如果是锐角的话贡献为 1,如果是钝角或直角的话贡献为 -2,最后相加除以 3 即可,可行性的证明可以直接列举一下三种三角形的情况:

  1. 锐角三角形:三个角都是锐角,计算出的贡献为 3 倍的面积
  2. 直角三角形:一个角为直角,其余两个角都为锐角,直角的提供 -2 倍的贡献,其余两个锐角提供 2 倍的贡献,可以相互抵消
  3. 钝角三角形:同直角三角形可以抵消

这样的话利用极角排序枚举每个角,将时间复杂度优化到 n^2logn,具体就是,O( n ) 枚举一个点记为 A,O( nlogn ) 以点 A 为中心进行极角排序,随后 O( n ) 枚举一条向量 AB,双指针寻找另一个向量的可行边界 AC,这样就可以快速计算出角 BAC 的贡献了,因为点积和叉积都满足分配率,就可以将叉积求解三角形面积的公式进行化简,用前缀和来进行辅助计算即可

值得一提的是,点积的几何意义是,两个向量的方向:

  1. AB * AC > 0 :角 BAC 大于 0 度,小于 90 度
  2. AB * AC = 0 :角 BAC 等于 90 度,也就是 AB 垂直于 AC
  3. AB * AC < 0 :角 BAC 大于 90 度,小于 180 度

然后叉积的几何意义是方向,右手定则,通俗一点来讲就是在 180 度以内,两条向量的相对位置,如果只关注叉积的数值的话,叉积的绝对值是两个向量所组成的平行四边形的面积

还有就是极角排序,需要先对向量进行象限排序,如果不在同一象限的话再按照叉积排序(叉积相同且象限相同的话,怎么排都无所谓了,因为在这个题目中是都会跳过的(因为两个向量共线,三角形的面积为 0 ,没必要过多的计算))

最后就是这个题目需要注意的一点了,数据范围给的特别大,显然用 double 是不行的了,double 的精度也就只有 1e15 的样子,所以所有的数据都需要用 long long 来储存,然后好多好多地方的运算都会爆 long long ,需要暂时用 __int128 来进行运算,代码中我用小写的 ll 代替 __int128 ,大写的 LL 代替的 long long

比较不错的一道题目吧,做完之后收获颇丰

代码:

#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;typedef long long LL;typedef __int128 ll;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=2e3+100;const int mod=998244353;const int inv3=332748118;LL ans,not_ans,sumx[N<<1],sumy[N<<1];int n;inline int sgn(LL x){if(x==0)return 0;if(x < 0)return -1;else return 1;
}struct Point{LL x,y;Point(){}Point(LL _x,LL _y){x = _x;y = _y;}void input(){scanf("%lld%lld",&x,&y);}bool operator == (Point b)const{return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;}bool operator < (Point b)const{return sgn(x-b.x)== 0?sgn(y-b.y)<0:x<b.x;}Point operator -(const Point &b)const{return Point(x-b.x,y-b.y);}Point operator +(const Point &b)const{return Point(x+b.x,y+b.y);}//叉积ll operator ^(const Point &b)const{return (ll)x*b.y - (ll)y*b.x;}//点积ll operator *(const Point &b)const{return (ll)x*b.x + (ll)y*b.y;}
}p[N],q[N<<1];inline int getxx(Point& a)
{if(sgn(a.x)>0 && sgn(a.y)>=0) return 1;if(sgn(a.x)<=0 && sgn(a.y)>0) return 2;if(sgn(a.x)<0 && sgn(a.y)<=0) return 3;if(sgn(a.x)>=0 && sgn(a.y)<0) return 4;
}bool cmp(Point a,Point b)
{if(getxx(a)!=getxx(b))return getxx(a)<getxx(b);return sgn(a^b)>0;
}void solve(int id)
{for(int i=1,j=1;i<=n;i++)if(i!=id)q[j++]=p[i]-p[id];sort(q+1,q+n,cmp);int n=::n-1;for(int i=1;i<=n;i++)q[i+n]=q[i];for(int i=1;i<=n<<1;i++){sumx[i]=(sumx[i-1]+q[i].x)%mod;sumy[i]=(sumy[i-1]+q[i].y)%mod;}int j=1,k=1,l=1;//相同极角的点的位置,锐角极角的位置,钝角极角的位置for(int i=1;i<=n;i++){while(j<i+n&&(q[i]^q[j])==0&&(q[i]*q[j])>0)j++;k=max(k,j);while(k<i+n&&(q[i]^q[k])>0&&(q[i]*q[k])>0)k++;l=max(l,k);while(l<i+n&&(q[i]^q[l])>0)l++;LL x1=(sumx[k-1]-sumx[j-1]+mod)%mod;LL y1=(sumy[k-1]-sumy[j-1]+mod)%mod;ans=(ans+((q[i].x%mod)*(y1)-(x1)*(q[i].y%mod))%mod+mod)%mod;LL x2=(sumx[l-1]-sumx[k-1]+mod)%mod;LL y2=(sumy[l-1]-sumy[k-1]+mod)%mod;not_ans=(not_ans+((q[i].x%mod)*(y2)-(x2)*(q[i].y%mod))%mod+mod)%mod;}
}int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);int w;cin>>w;while(w--){ans=0,not_ans=0;scanf("%d",&n);for(int i=1;i<=n;i++)p[i].input();for(int i=1;i<=n;i++)solve(i);printf("%lld\n",(ans-not_ans+mod-not_ans+mod)%mod*inv3%mod);}return 0;
}

HihoCoder - 1879 Rikka with Triangles(极角排序求所有锐角三角形的面积)相关推荐

  1. L3-021 神坛(极角排序求三角形最小面积)

    在古老的迈瑞城,巍然屹立着 n 块神石.长老们商议,选取 3 块神石围成一个神坛.因为神坛的能量强度与它的面积成反比,因此神坛的面积越小越好.特殊地,如果有两块神石坐标相同,或者三块神石共线,神坛的面 ...

  2. L3-021 神坛 极角排序

    L3-021 神坛 (30 分) 在古老的迈瑞城,巍然屹立着 n 块神石.长老们商议,选取 3 块神石围成一个神坛.因为神坛的能量强度与它的面积成反比,因此神坛的面积越小越好.特殊地,如果有两块神石坐 ...

  3. 牛客 数三角(求多少个钝角三角形 极角排序)

    晚上的时候PC问了一下这玩意,回忆一下极角排序 相关链接: How Many Triangles HDU - 5784(极角排序,双指针) 2019秦皇岛A - Angle Beats Gym - 1 ...

  4. BZOJ 1132 [POI2008]Tro(极角排序)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1132 [题目大意] 平面上有N个点. 求出所有以这N个点为顶点的三角形的面积和(N&l ...

  5. bzoj 1914: [Usaco2010 OPen]Triangle Counting 数三角形——极角排序

    Description 在一只大灰狼偷偷潜入Farmer Don的牛群被群牛发现后,贝西现在不得不履行着她站岗的职责.从她的守卫塔向下瞭望简直就是一件烦透了的事情.她决定做一些开发智力的小练习,防止她 ...

  6. codeforces 598C C. Nearest vectors(极角排序)

    题目链接: C. Nearest vectors time limit per test 2 seconds memory limit per test 256 megabytes input sta ...

  7. poj2280--Amphiphilic Carbon Molecules(扫描线+极角排序+转换坐标)

    poj2280--Amphiphilic Carbon Molecules(扫描线+极角排序+转换坐标) 题目链接:点击打开链接 题目大意:给出n个点的坐标.每一个点有一个值0或者1,如今有一个隔板( ...

  8. BZOJ.1132.[POI2008]Tro(极角排序)

    BZOJ 洛谷 考虑暴力,每次枚举三个点,答案就是\(\frac12\sum_{k<j<i}(i-k)\times(j-k)\). 注意到叉积有分配率,所以固定\(k\),枚举\(i,j\ ...

  9. 【BZOJ-1913】signaling信号覆盖 极角排序 + 组合

    1913: [Apio2010]signaling 信号覆盖 Time Limit: 20 Sec  Memory Limit: 64 MB Submit: 1232  Solved: 506 [Su ...

最新文章

  1. angular-fullstack test
  2. Ubuntu下ibus在firefox浏览器中选中即删除的解决办法
  3. python opencv 批量将视频转化为图片
  4. 【AI-1000问】为什么深度学习图像分类的输入多是224*224
  5. js plugin--headroom
  6. 在一个风景秀丽的小镇,一天早上,有N名晨跑爱好者(编号1~N)沿着优雅的江边景观道朝同一方向进行晨跑
  7. dataframe for循环 筛选_Python循环12种超强写法,又快又省内存
  8. 【安全牛学习笔记】抓包嗅探
  9. 电视盒子内存测试软件,电视盒子内存太小怎么办?当贝市场一招扩充内存
  10. matlab积分器的工作原理,转 Simulink积分器详解(图)
  11. R语言进行主成分分析PCA和探索性因子分析EFA的常用步骤:准备资料、选择因子模型、提取多少主成分/因子、提取主成分或者因子、旋转主成分或者因子、数据结果解读、计算主成分或因子得分(或者系数)
  12. 健全营销体制是打造营销生态系统的命脉
  13. bootstrap-tagsinput操作标签对象,实现从表格中选人和移除
  14. 计算机前程似锦教程图片,这三个专业非常学起很累,但毕业后前程似锦
  15. PDF电子签名申请与设置方法
  16. Android随机点名器,Excel基础知识-详解随机点名器
  17. 使用Socket实现账号密码验证
  18. 收费软件推广模式探索1
  19. JAVA实现腾讯企业邮箱发邮件
  20. 《动手实现一款简单的拦阻球游戏》

热门文章

  1. SpringSecurity注销功能
  2. Nacos配置管理-Nacos实现配置管理
  3. Nginx的Gzip模块配置指令(三)
  4. 编写一个Zipkin Server
  5. SimpleExecutor.doQuery()-执行的StatementHandler 的query()方法
  6. 在Spring 框架中如何更有效的使用JDBC?
  7. aop简介-基于jdk的动态代理
  8. 自定义线程池-参数设计分析
  9. http响应协议分析
  10. ReactJS入门之环境搭建以及编写HelloWorld程序