CF611G New Year and Cake

XXVII.CF611G New Year and Cake

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

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

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

我们记点 pi,pi+1,,pj 构成的图形为 多边形ij

于是我们对于每个 pi,考虑求出其后方最后一个 pj,使得 S多边形ijarea2。(当然,这里的 pj 是循环意义下的)。按照套路,这应该用two-pointers就能轻松解决。

然后,对于每一个 i+2kjS多边形ik 都能作为 nowarea 被计算。

于是我们现在要求出 k=i+2jarea2S多边形ik。拆开,得到 (ji1)area2k=i+2jS多边形ik

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

我们考虑,当 i 增加 1 时,S多边形ik,减少 Spipi+1pk。其可被表示成 (pi+1pi)×(pkpi)

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

(pi+1pi)(k=i+2j(pkpi))

再拆,得到

(pi+1pi)((k=i+2jpk)(ji1)pi)

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

复杂度 O(n)

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

代码:

#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 @   Troverld  阅读(47)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示