- 给定一个(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;//总情况数下的面积总和减去求出贡献的两倍
}