[OICamp 2016 Day 1][JZOJ4773]凸包
来源:互联网 发布:php九大接口编程 编辑:程序博客网 时间:2024/06/14 18:33
题目大意
给定二维平面
对于每一个点,都有
求所有黑点构成的凸包上点数的期望,答案乘上
注意:这里的凸包指的是非退化凸包,凸包上任意两点不重合,任意三点不共线!
题目分析
由于乘上了
先不考虑共线和重点情况。
从点入手,统计每个点对答案的贡献似乎很难。因为一个点在凸包内的充分必要条件是写不出来的。
但是我们可以发现,由于凸包是闭合图形,因此边数与点数相等,因此,统计边数之和与统计点数之和等价(当然,单个点凸包特殊处理,还有两个点构成的凸包有两条边!!!)。
我们枚举边的起点,然后对其余所有点极角排序。依次枚举边的终点,一条边(注意我们规定它是有向线段)在凸包内当且仅当该线段右手方向(你也可以规定左手方向)没有任何点,并且与它共线的点不能在这条线段外。其余的点取和不取,对凸包形态都没有影响。记这些没有影响的点个数为
怎么统计这种点的个数呢?当我们枚举的有向线段在一二象限上时,我们可以使用一个指针来得到第一个不在这条线段右手方向的点,那在这个指针前一位就是第一个合法的点。否则使用一个指针来得到第一个在这条线段右手方向的点,在这个指针的前一位开始就是要减掉的不合法点。
考虑重点情况,其实没有多大影响。我们将所有相同点缩成一个。设要统计边
至于共线情况,我们令极角排序第二关键字是长度。然后有向线段内的所有点都是可以随便选的,计入
其实这题细节还挺多的,就交给读者们自己思考了,当然也可以参考一下我的代码。
时间复杂度
代码实现
#include <algorithm>#include <iostream>#include <cstdio>#include <cctype>#include <cmath>using namespace std;typedef long long LL;inline int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar(); while (isdigit(ch)) x=x*10+ch-'0',ch=getchar(); return x*f;}const int INF=2000000000;const int MOD=1000000007;const int N=2050;struct P{ int x,y,cnt; inline P(int x_=0,int y_=0,int cnt_=0){x=x_,y=y_,cnt=cnt_;}}ps[N],pn[N];bool operator!=(P a,P b){return a.x!=b.x||a.y!=b.y;}bool cmp1(P a,P b){return a.x<b.x||a.x==b.x&&a.y<b.y;}inline P operator-(P a,P b){return P(a.x-b.x,a.y-b.y);}inline P operator+(P a,P b){return P(a.x+b.x,a.y+b.y);}inline LL operator*(P a,P b){return 1ll*a.x*b.x+1ll*a.y*b.y;}inline LL operator^(P a,P b){return 1ll*a.x*b.y-1ll*a.y*b.x;}inline int sgn(LL x){return (!x)?0:(x>0?1:-1);}inline int direct(P a,P b){return sgn(a^b);}inline int quadrant(P a){ if (a.y>=0&&a.x>0) return 0; if (a.x<=0&&a.y>0) return 1; if (a.y<=0&&a.x<0) return 2; if (a.x>=0&&a.y<0) return 3;}inline LL mod2(P a){return a*a;}bool cmp2(P a,P b){ int qa=quadrant(a),qb=quadrant(b),d=direct(a,b); return qa<qb||qa==qb&&(d>0||!d&&mod2(a)<mod2(b));}int pw[N],sum[N];int ans,n;void solve(){ for (int i=1,tot,cur,col,right;i<=n;i++) { (ans+=pw[ps[i].cnt]-1)%=MOD,tot=0; for (int j=1;j<=n;j++) if (i!=j) pn[++tot]=ps[j]-ps[i],pn[tot].cnt=ps[j].cnt; sort(pn+1,pn+1+tot,cmp2); col=0,cur=1; bool flag=0; sum[0]=0; for (int j=1;j<=tot;j++) sum[j]=sum[j-1]+pn[j].cnt; for (int j=1;j<=tot;j++) { if (!flag) while (cur<=tot&&direct(pn[cur],pn[j])<=0) cur++; if (!flag&&quadrant(pn[j])>=2) flag=cur=1; if (flag) while (cur<=tot&&(direct(pn[cur],pn[j])<0||!direct(pn[cur],pn[j])&&quadrant(pn[cur])!=quadrant(pn[j]))) cur++; if (j==1||direct(pn[j],pn[j-1])||quadrant(pn[j])!=quadrant(pn[j-1])) col=0; right=sum[j-1]-col+(flag?-sum[cur-1]:sum[tot]-sum[cur-1]); (ans+=1ll*(pw[ps[i].cnt]-1)*(pw[pn[j].cnt]-1)%MOD*pw[right+col]%MOD)%=MOD; col+=pn[j].cnt; } }}int main(){ freopen("random.in","r",stdin),freopen("random.out","w",stdout); n=read(),pw[0]=1; for (int i=1;i<=n;i++) pw[i]=1ll*pw[i-1]*2%MOD; for (int i=1,x,y;i<=n;i++) x=read(),y=read(),ps[i]=P(x,y); sort(ps+1,ps+1+n,cmp1),ps[0]=P(-INF,-INF); int df=0; for (int i=1,l=0;i<=n;i++) { if (ps[i]!=ps[i-1]) l=i; ps[l].cnt++; } for (int i=1;i<=n;i++) if (ps[i].cnt) ps[++df]=ps[i]; for (int i=df+1;i<=n;i++) ps[i]=P(0,0); n=df; solve(); printf("%d\n",ans); fclose(stdin),fclose(stdout); return 0;}
- [OICamp 2016 Day 1][JZOJ4773]凸包
- JZOJ4773. 凸包
- [OICamp 2016 Day 5/JZOJ4779]鞍点
- JZOJ4779 【GDOI2017模拟9.14】鞍点(OICamp 2016 Day 5 T1) 计数问题
- [OICamp 2016 Day5A]鞍点
- JZOJ4780 【GDOI2017模拟9.14】三角形 (OICamp 2016 Day 5 T2) 可证明复杂度的有技巧暴力
- OICamp 2016 Day2 路径数
- Day 1
- day 1
- DAY 1
- day 1
- day-1
- DAY 1
- Day 1
- day(1)
- day 1
- Day 1
- Day 1
- hdu 5878 I Count Two Three 丑数 二分
- EL表达式
- tp 学习基础
- poj 1011 Sticks
- HDU 2047 - 阿牛的EOF牛肉串(递推)
- [OICamp 2016 Day 1][JZOJ4773]凸包
- C++实现数据结构-队列
- 初识bitset
- hdu5894 hannnnah_j’s Biological Test
- centos6.5环境Redis下载及编译安装
- AngularJS 1.x 和TypeScript(ES6)开发的最佳实践
- IOS手机浏览器无法获取网站视频与音乐,安卓与电脑都可以
- JavaEE之静态,非静态的调用
- 算法16_笔试_数字逻辑推理题2