CF611G New Year and Cake

XXVII.CF611G New Year and Cake

做题时居然忘记了叉积满足分配律/jk

我们先将图形翻转成为逆时针排布。

首先,我们发现,若总图形的面积是 \(area\),切完后,较小一半的面积是 \(nowarea\),则贡献是 \(area-2nowarea\)

我们记点 \(p_i,p_{i+1},\dots,p_j\) 构成的图形为 \(\text{多边形}i\sim j\)

于是我们对于每个 \(p_i\),考虑求出其后方最后一个 \(p_j\),使得 \(S_{\text{多边形}i\sim j}\leq\dfrac{area}{2}\)。(当然,这里的 \(p_j\) 是循环意义下的)。按照套路,这应该用two-pointers就能轻松解决。

然后,对于每一个 \(i+2\leq k\leq j\)\(S_{\text{多边形}i\sim k}\) 都能作为 \(nowarea\) 被计算。

于是我们现在要求出 \(\sum\limits_{k=i+2}^jarea-2S_{\text{多边形}i\sim k}\)。拆开,得到 \((j-i-1)area-2\sum\limits_{k=i+2}^jS_{\text{多边形}i\sim k}\)

前一半很好算,关键是后一半。随着右边界 \(j\) 的增加,此和是很好维护的;但是,当左边界 \(i\) 增加时,和就不太好维护了。

我们考虑,当 \(i\) 增加 \(1\) 时,\(S_{\text{多边形}i\sim k}\),减少 \(S_{\triangle p_ip_{i+1}p_k}\)。其可被表示成 \((p_{i+1}-p_i)\times(p_k-p_i)\)

考虑不同的 \(p_k\),因为叉积满足分配律,所以当 \(i\) 增加 \(1\) 时,后面的东西减少了

\[(p_{i+1}-p_i)\Big(\sum\limits_{k=i+2}^j(p_k-p_i)\Big) \]

再拆,得到

\[(p_{i+1}-p_i)\Bigg(\Big(\sum\limits_{k=i+2}^jp_k\Big)-(j-i-1)p_i\Bigg) \]

明显此处 \(\Sigma\) 内的东西就很好维护了,于是我们原本想维护的那一大坨也就可以维护了。

复杂度 \(O(n)\)

(注意,当比较面积是否超过 \(area/2\) 时,此处的面积不能取模;然而,其它时候(特别是维护 \(\sum p_k\) 的时候),模是一定要取的,所以解决方案是写一套自动取模的向量模板,再写一套不取模的)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod=1e9+7;
int n,res;
struct MV{//moduloed vector
	int x,y;
	MV(){x=y=0;}
	MV(int X,int Y){x=(X+mod)%mod,y=(Y+mod)%mod;}
	friend MV operator +(const MV &u,const MV &v){return MV((u.x+v.x)%mod,(u.y+v.y)%mod);}
	friend MV operator -(const MV &u,const MV &v){return MV((u.x+mod-v.x)%mod,(u.y+mod-v.y)%mod);}
	friend MV operator *(const MV &u,const int &v){return MV(1ll*u.x*v%mod,1ll*u.y*v%mod);}
	friend int operator &(const MV &u,const MV &v){return (1ll*u.x*v.y%mod-1ll*u.y*v.x%mod+mod)%mod;}//cross times
	friend int operator |(const MV &u,const MV &v){return (1ll*u.x*v.x%mod+1ll*u.y*v.y%mod)%mod;}//point times
	void operator +=(const MV &v){(x+=v.x)%=mod,(y+=v.y)%=mod;}
	void operator -=(const MV &v){(x+=mod-v.x)%=mod,(y+=mod-v.y)%=mod;}
	void read(){scanf("%d%d",&x,&y),(x+=mod)%=mod,(y+=mod)%=mod;}
	void print(){printf("(%d,%d)",x,y);}
}q[500100];
struct OV{//ordinary vector
	int x,y;
	OV(){}
	OV(int X,int Y){x=X,y=Y;}
	friend OV operator +(const OV &u,const OV &v){return OV(u.x+v.x,u.y+v.y);}
	friend OV operator -(const OV &u,const OV &v){return OV(u.x-v.x,u.y-v.y);}
	friend ll operator &(const OV &u,const OV &v){return 1ll*u.x*v.y-1ll*u.y*v.x;}//cross times
	friend ll operator |(const OV &u,const OV &v){return 1ll*u.x*v.x+1ll*u.y*v.y;}//point times
	void read(){scanf("%d%d",&x,&y);}
	void print(){printf("(%d,%d)",x,y);}
}p[500100];
ull area;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)p[n-i].read(),q[n-i]=MV(p[n-i].x,p[n-i].y);
	for(int i=0;i<n;i++)area+=p[i]&p[(i+1)%n];
	ull nowarea=0;
	int sumarea=0;
	MV v;
	for(int i=0,j=0;i<n;i++){
		while(((nowarea+((p[j]-p[i])&(p[(j+1)%n]-p[i])))<<1)<=area){
			v+=q[(j+1)%n];
			nowarea+=(p[j]-p[i])&(p[(j+1)%n]-p[i]);
			(sumarea+=nowarea%mod)%=mod;
			(++j)%=n;
		}
		(res+=(area%mod*((j-i+n-1)%n)%mod-2*sumarea%mod+mod)%mod)%=mod;
		nowarea-=(p[(i+1)%n]-p[i])&(p[j]-p[i]),v-=q[(i+1)%n];
		(sumarea+=mod-((q[(i+1)%n]-q[i])&(v-q[i]*((j-i+n-1)%n)))%mod)%=mod;
	}
	printf("%d\n",res);
	return 0;
}

posted @ 2021-04-05 20:53  Troverld  阅读(43)  评论(0编辑  收藏  举报