BZOJ2191 : Split

$O(n^2)$枚举公共部分,需要满足以下条件:

  1. 公共部分的(转角,边长,转角,边长,转角,...)序列相等。
  2. 两端的角度之和都不超过$180$°。
  3. 剩下部分(包括两端)的角度不超过$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;
}

  

猜你喜欢

转载自www.cnblogs.com/clrs97/p/12204007.html