• 【CF611G】New Year and Cake(计算几何)


    点此看题面

    • 给定一个(n)个点的凸多边形。
    • 求出多边形由每条对角线划分成的两部分面积之差的和。
    • (nle5 imes10^5)

    双指针判正负贡献

    考虑双指针,可以维护出从一个顶点出发,哪一半左边面积大,哪一半右边面积大。

    方便起见,我们只求出较小部分面积的贡献,结束时用所有情况下的总面积之和减去两倍该贡献即可得出答案。

    由于实际实现中两半面积相同时候可能会出现一些问题,因此特殊处理该部分,不把此时的面积计入贡献中,记录这种情况的个数并在最后减去。

    在切换顶点的时候,如果直接记录面积是很难维护出面积的变化量的,因此利用叉积的分配律,维护好贡献向量之和,并在切换顶点的时候更新即可。

    注意取模的问题,一般向量的面积需要比大小,必须开(unsigned long long)而不能取模;而贡献向量的和向量是用于计算贡献的,并不会被用于比大小,且显然和其他向量相叉可能会达到(2 imes10^{24})级别,因此必须取模。

    代码:(O(n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 500000
    #define X 1000000007
    #define ull unsigned long long
    using namespace std;
    int n;struct P
    {
    	int x,y;I P(CI a=0,CI b=0):x(a),y(b){}
    	I P operator - (Con P& o) Con {return P(x-o.x,y-o.y);}
    }p[2*N+5];
    struct MP
    {
    	int x,y;I MP(CI a=0,CI b=0):x(a),y(b){}I MP(Con P& p):x((p.x%X+X)%X),y((p.y%X+X)%X){} 
    	I void operator += (Con MP& o) {x=(x+o.x)%X,y=(y+o.y)%X;}
    	I void operator -= (Con MP& o) {x=(x-o.x+X)%X,y=(y-o.y+X)%X;}
    	I MP operator * (CI o) Con {return MP(1LL*x*o%X,1LL*y*o%X);}
    };
    I ull S (Con P& A,Con P& B) {return abs(1LL*A.x*B.y-1LL*A.y*B.x);}//用于比大小的面积
    I int S (Con MP& A,Con MP& B) {return (1LL*A.x*B.y-1LL*A.y*B.x%X+X)%X;}//用于计算贡献的面积
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define D isdigit(oc=tc())
    	int Ff;char oc,FI[FS],*FA=FI,*FB=FI;
    	Tp I void read(Ty& x) {x=0,Ff=1;W(!D) Ff=oc^'-'?1:-1;W(x=(x<<3)+(x<<1)+(oc&15),D);x*=Ff;}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }using namespace FastIO;
    int main()
    {
    	RI i,j;for(read(n),i=1;i<=n;++i) read(p[i].x,p[i].y),p[n+i]=p[i];
    	ull s=0;for(i=2;i^n;++i) s+=S(p[i]-p[1],p[i+1]-p[1]);//计算总面积
    	RI c=0,w=0,t=0;ull f=0,g;MP sp;for(i=j=1;i<=n;++i)//枚举顶点
    	{
    		W(1) if(2*(f+(g=S(p[j]-p[i],p[j+1]-p[i])))<s) w=(w+(f+=g))%X,sp+=p[++j]-p[i];else {2*(f+g)==s&&++c;break;}//双指针移动
    		t=(t+w)%X,f-=S(p[j]-p[i],p[j]-p[i+1]),w=(w-S(sp,p[i+1]-p[i])+X)%X,sp-=MP(p[i+1]-p[i])*(j-i);//计算贡献,然后切换端点
    	}return printf("%d
    ",((1LL*n*(n-3)-c)/2%X*(s%X)-2*t+2*X)%X),0;//总情况数下的面积总和减去求出贡献的两倍
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Linux LAMP架构搭建
    Linux 系统版本查询
    Linux 安装本地 yum源
    Linux 虚拟机安装vmware tools
    随记分页码
    flexigrid 修改json格式
    Asp.Net MVC及Web API框架配置会碰到的几个问题及解决方案
    web api 文档声明
    android UI
    Sending HTML Form Data
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF611G.html
Copyright © 2020-2023  润新知