• 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;
    }
    

  • 相关阅读:
    博客最新博文通告
    博文快速导航
    创业
    央行回应中国版数字货币:与人民币等价 不会让钱贬值
    高屋建瓴
    高层人对事的处理
    老板的区别
    沟通的四大法则
    赚钱规则
    合伙做生意的原则
  • 原文地址:https://www.cnblogs.com/Troverld/p/14619443.html
Copyright © 2020-2023  润新知