BZOJ2191 : Split
$O(n^2)$枚举公共部分,需要满足以下条件:
- 公共部分的(转角,边长,转角,边长,转角,...)序列相等。
- 两端的角度之和都不超过$180$°。
- 剩下部分(包括两端)的角度不超过$180$°。
(3)可以直接在枚举的时候判断掉,对于(1)和(2),可以将(1)哈希,对于哈希值相同的角度对$(a,b)$,将它们按照$a$排序,然后在双指针时维护$b$的最小值即可。
时间复杂度$O(n^2\log n)$。
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; typedef double ld; typedef unsigned long long ll; const int N=2010; const ld eps=1e-9,pi=acos(-1.0); inline int sgn(ld x){ if(x>eps)return 1; if(x<-eps)return -1; return 0; } int n,m,ce,i,j,r[N],cp;ld f[N],g[N],h[N],sl[N<<1],sr[N<<1];ll vl[N<<1],vr[N<<1],p[N<<1]; struct P{ ld x,y; P(){} P(ld _x,ld _y){x=_x,y=_y;} P operator-(const P&b)const{return P(x-b.x,y-b.y);} ld operator*(const P&b)const{return x*b.x+y*b.y;} ld len(){return hypot(x,y);} void read(){scanf("%lf%lf",&x,&y);} }a[N],b[N]; struct E{ ll l;int r;ld a,b; E(){} E(ll _l,int _r,ld _a,ld _b){l=_l,r=_r,a=_a,b=_b;} }e[2000005]; struct Num{ ld x;int p; Num(){} Num(ld _x,int _p){x=_x,p=_p;} }pool[N<<2]; struct EV{ ld a,b; EV(){} EV(ld _a,ld _b){a=_a,b=_b;} }el[N],er[N]; inline bool cmp(const Num&a,const Num&b){return a.x<b.x;} inline bool cmpe(const E&a,const E&b){return a.l<b.l;} inline bool cmpev(const EV&a,const EV&b){return a.a<b.a;} inline ld cross(const P&a,const P&b){return a.x*b.y-a.y*b.x;} inline void initl(int n,P*a,ld*s){ int i,j; ld area=0; for(i=0;i<n;i++)area+=cross(a[i],a[(i+1)%n]); if(area<0)reverse(a,a+n); for(i=0;i<n;i++){ P pre=a[(i+n-1)%n],suf=a[(i+1)%n]; f[i]=acos((pre-a[i])*(suf-a[i])/(pre-a[i]).len()/(suf-a[i]).len()); g[i]=cross(a[i]-pre,suf-a[i]); h[i]=(a[i]-suf).len(); } for(i=0;i<=n+n;i++){ if(i>=n)f[i]=f[i%n],g[i]=g[i%n]; s[i<<1]=g[i]; s[i<<1|1]=h[i%n]; } for(r[n*2+1]=n*2+1,i=n*2;~i;i--)r[i]=sgn(g[i])>0?r[i+1]:i-1; for(i=0;i<n;i++)if(sgn(g[i])>0)for(j=i+n-1;j>i;j--)if(sgn(g[j])>0){ if(r[j+1]<i+n-1)break; e[++ce]=E(-(i<<1|1),(j<<1)-1,f[i],f[j]); } } inline void initr(int n,P*a,ld*s){ int i,j; ld area=0; for(i=0;i<n;i++)area+=cross(a[i],a[(i+1)%n]); if(area>0)reverse(a,a+n); for(i=0;i<n;i++){ P pre=a[(i+n-1)%n],suf=a[(i+1)%n]; f[i]=acos((pre-a[i])*(suf-a[i])/(pre-a[i]).len()/(suf-a[i]).len()); g[i]=cross(a[i]-pre,suf-a[i]); h[i]=(a[i]-suf).len(); } for(i=0;i<=n+n;i++){ if(i>=n)f[i]=f[i%n],g[i]=g[i%n]; s[i<<1]=g[i]; s[i<<1|1]=h[i%n]; } for(r[n*2+1]=n*2+1,i=n*2;~i;i--)r[i]=sgn(g[i])<0?r[i+1]:i-1; for(i=0;i<n;i++)if(sgn(g[i])<0)for(j=i+n-1;j>i;j--)if(sgn(g[i])<0){ if(r[j+1]<i+n-1)break; e[++ce]=E(i<<1|1,(j<<1)-1,f[i],f[j]); } } inline bool check(int n,int m){ if(!n||!m)return 0; sort(el+1,el+n+1,cmpev); sort(er+1,er+m+1,cmpev); int i,j;ld t=100; for(i=n,j=1;i;i--){ while(j<=m&&sgn(el[i].a+er[j].a-pi)<=0)t=min(t,er[j++].b); if(sgn(el[i].b+t-pi)<=0)return 1; } return 0; } inline bool solve(){ int i,j,k,l,r; cp=0; for(i=0;i<=n*4+1;i++)pool[cp++]=Num(sl[i],i<<1); for(i=0;i<=m*4+1;i++)pool[cp++]=Num(sr[i],i<<1|1); sort(pool,pool+cp,cmp); ll ran=998244353; for(i=0;i<cp;i=j){ for(j=i;j<cp&&!sgn(pool[i].x-pool[j].x);j++); for(k=i;k<j;k++)if(pool[k].p&1)vr[pool[k].p>>1]=ran;else vl[pool[k].p>>1]=ran; ran=ran*1000000007+13331; } for(i=1;i<=n*4+1;i++)vl[i]+=vl[i-1]*233; for(i=1;i<=m*4+1;i++)vr[i]+=vr[i-1]*233; for(p[0]=i=1;i<=m*4+1||i<=n*4+1;i++)p[i]=p[i-1]*233; for(i=1;i<=ce;i++){ l=e[i].l,r=e[i].r; if(l<0){ e[i].l=vl[r]-vl[-l-1]*p[r+l+1]; e[i].r=0; }else{ e[i].l=vr[r]-vr[l-1]*p[r-l+1]; e[i].r=1; } } sort(e+1,e+ce+1,cmpe); for(i=1;i<=ce;i=j){ for(j=i;j<=ce&&e[i].l==e[j].l;j++); int cl=0,cr=0; for(k=i;k<j;k++)if(e[k].r)er[++cr]=EV(e[k].a,e[k].b);else el[++cl]=EV(e[k].a,e[k].b); if(check(cl,cr))return 1; } return 0; } int main(){ while(~scanf("%d",&n)){ for(i=0;i<n;i++)a[i].read(); scanf("%d",&m); for(i=0;i<m;i++)b[i].read(); for(i=0;i<2;i++){ ce=0; initl(n,a,sl); initr(m,b,sr); if(solve()){ puts("1"); break; } swap(n,m); for(j=0;j<n||j<m;j++)swap(a[j],b[j]); } if(i==2)puts("0"); } return 0; }