首页 > 代码库 > BZOJ3490 : Pa2011 Laser Pool

BZOJ3490 : Pa2011 Laser Pool

与横线以及竖线的交点个数很容易求,那么只要求出横线竖线交点与运动轨迹的交点数即可。

运动轨迹可以划分成若干条贯穿边界的斜线,对于第一条和最后一条,可以用bitset暴力统计。

对于中间的部分,斜线都是完整的,可以FFT预处理。

时间复杂度$O(n\log n+\frac{nq}{32})$。

 

#include<cstdio>#include<cmath>#include<algorithm>using namespace std;typedef unsigned int U;const int N=100010,M=10010,L=262150;int n,m,cb,ce,i,j,ab[N*2],arb[N*2],rab[N*2],rarb[N*2],g[65540];char a[N],b[N];struct Que{int x,y,vx,vy,t,ans;}e[M];inline int popcount(U x){return g[x>>16]+g[x&65535];}struct BIT{  U v[N/32+5];  void clr(){for(int i=0;i<=cb;i++)v[i]=0;}  U get(int x){return v[x>>5]>>(x&31)&1;}  void set(int x,U y){if((v[x>>5]>>(x&31)&1)^y)v[x>>5]^=1U<<(x&31);}  void shl(int x,int y){    int A=y>>5,B=y&31,C=(32-B)&31,D=x>>5,E=(D<<5)+31;    for(int i=x;i<=E;i++)set(i,get(i+y));    for(int i=D+1;i<=cb;i++){      v[i]=v[i+A]>>B;      if(C)v[i]|=v[i+A+1]<<C;    }  }  void copy(int x,int y,const BIT&p){for(int i=x;i<=y;i++)v[i]=p.v[i];}  void And(int x,int y,const BIT&p){for(int i=x;i<=y;i++)v[i]&=p.v[i];}  int count(int x,int y){    int A=x>>5,B=y>>5,C,ret=0;    if(A==B){      for(int i=x;i<=y;i++)if(v[A]>>(i&31)&1)ret++;      return ret;    }    for(int i=A+1;i<B;i++)ret+=popcount(v[i]);    C=(A<<5)+31;    for(int i=x;i<=C;i++)if(v[A]>>(i&31)&1)ret++;    C=B<<5;    for(int i=C;i<=y;i++)if(v[B]>>(i&31)&1)ret++;    return ret;  }}bA,bB,brA,brB,tA,tB;inline void read(int&a){  char c;bool f=0;a=0;  while(!((((c=getchar())>=‘0‘)&&(c<=‘9‘))||(c==‘-‘)));  if(c!=‘-‘)a=c-‘0‘;else f=1;  while(((c=getchar())>=‘0‘)&&(c<=‘9‘))(a*=10)+=c-‘0‘;  if(f)a=-a;}namespace FFT{int k,j,pos[L];const double pi=acos(-1.0);struct comp{  double r,i;comp(double _r=0,double _i=0){r=_r,i=_i;}  comp operator+(const comp&x){return comp(r+x.r,i+x.i);}  comp operator-(const comp&x){return comp(r-x.r,i-x.i);}  comp operator*(const comp&x){return comp(r*x.r-i*x.i,r*x.i+i*x.r);}}a[L],ra[L],b[L],rb[L],c[L];void FFT(comp a[],int n,int t){  for(int i=1;i<n;i++)if(i<pos[i])swap(a[i],a[pos[i]]);  for(int d=0;(1<<d)<n;d++){    int m=1<<d,m2=m<<1;    double o=pi*2/m2*t;comp _w(cos(o),sin(o));    for(int i=0;i<n;i+=m2){      comp w(1,0);      for(int j=0;j<m;j++){        comp&A=a[i+j+m],&B=a[i+j],t=w*A;        A=B-t;B=B+t;w=w*_w;      }    }  }  if(t==-1)for(int i=0;i<n;i++)a[i].r/=n;}void work(){  for(k=1;k<=n||k<=m;k<<=1);k<<=1;  j=__builtin_ctz(k)-1;  for(i=0;i<k;i++)pos[i]=pos[i>>1]>>1|((i&1)<<j);  for(i=1;i<=n;i++)a[i].r=ra[n-i+1].r=::a[i];  for(i=1;i<=m;i++)b[i].r=rb[m-i+1].r=::b[i];  FFT(a,k,1),FFT(ra,k,1),FFT(b,k,1),FFT(rb,k,1);  for(i=0;i<k;i++)c[i]=a[i]*b[i];  FFT(c,k,-1);  for(i=1;i<=n+m;i++)ab[i]=(int)(c[i].r+0.5);  for(i=0;i<k;i++)c[i]=a[i]*rb[i];  FFT(c,k,-1);  for(i=1;i<=n+m;i++)arb[i]=(int)(c[i].r+0.5);  for(i=0;i<k;i++)c[i]=ra[i]*b[i];  FFT(c,k,-1);  for(i=1;i<=n+m;i++)rab[i]=(int)(c[i].r+0.5);  for(i=0;i<k;i++)c[i]=ra[i]*rb[i];  FFT(c,k,-1);  for(i=1;i<=n+m;i++)rarb[i]=(int)(c[i].r+0.5);}}namespace Solve{bool a[N],b[N];int sa[N],sb[N];int cnt,idx[4][N],idy[4][N];int tot,st[N*8],en[N*8],v[N*8],pos[N*8],cur,q[N*8],sw[N*8];long long sl[N*8];struct E{int sx,sy,ex,ey,len,w,d,nxt;}f[N*8];inline bool check(int x,int y){return b[x]&&a[y];}inline int abs(int x){return x>0?x:-x;}inline int&getid(int x,int y,int d){  if(y==1||y==n)return idx[d][x];  return idy[d][y];}inline void makerev(int x){  f[x].sx=f[x-1].ex;  f[x].sy=f[x-1].ey;  f[x].ex=f[x-1].sx;  f[x].ey=f[x-1].sy;  f[x].w=f[x-1].w;  f[x].d=(f[x-1].d+2)&3;}inline int getnxt(int x,int y,int d){  if(d==0){    if(x<m&&y==n)return getid(x,y,(d+1)&3);    if(y==n)return getid(x,y,(d+2)&3);    return getid(x,y,(d+3)&3);  }  if(d==2){    if(x>1&&y==1)return getid(x,y,(d+1)&3);    if(y==1)return getid(x,y,(d+2)&3);    return getid(x,y,(d+3)&3);  }  if(d==1){    if(x<m&&y==1)return getid(x,y,(d+3)&3);    if(y==1)return getid(x,y,(d+2)&3);    return getid(x,y,(d+1)&3);  }  if(x>1&&y==n)return getid(x,y,(d+3)&3);  if(y==n)return getid(x,y,(d+2)&3);  return getid(x,y,(d+1)&3);}inline int cal(int x,int t,int n,int*s){  if(x+t<=n)return s[x+t]-s[x-1];  t-=n-x;  int ret=s[n-1]-s[x-1];  ret+=t/(n+n-2)*(s[n]+s[n-1]-s[1]);  t%=n+n-2;  if(t<n)return ret+s[n]-s[n-t-1];  return ret+s[n]-s[1]+s[t-n+2];}inline int search(int L,int r,int x){  int l=L,t=L-1,mid;  while(l<=r)if(sl[mid=(l+r)>>1]-sl[L-1]<=x)l=(t=mid)+1;else r=mid-1;  return t;}inline void ask(int x,int y,int t,int p){  int&ans=e[p].ans;  ans=cal(x,t,m,sb)+cal(y,t,n,sa);  int ex=m,ey=y-x+m;  if(ey>n)ey=n,ex=x-y+n;  int d=ex-x;  if(t<=d){    tA.copy(y>>5,cb,bA);    tB.copy(x>>5,cb,bB);    tB.shl(0,x);    tA.shl(0,y);    tA.And(0,t>>5,tB);    ans-=tA.count(0,t);    return;  }  if(d){    tA.copy(y>>5,cb,bA);    tB.copy(x>>5,cb,bB);    tB.shl(0,x);    tA.shl(0,y);    tA.And(0,(d-1)>>5,tB);    ans-=tA.count(0,d-1);  }  t-=d;  int o=getnxt(ex,ey,0);  int l=st[v[o]],r=en[v[o]];  o=pos[o];  int u=search(o,r,t);  ans-=sw[u]-sw[o-1];  t-=sl[u]-sl[o-1];  o=u+1;  if(o>r){    ans-=t/(sl[r]-sl[l-1])*(sw[r]-sw[l-1]);    t%=sl[r]-sl[l-1];    u=search(l,r,t);    ans-=sw[u]-sw[l-1];    t-=sl[u]-sl[l-1];    o=u+1;  }  o=q[o];  x=f[o].sx,y=f[o].sy;  if(f[o].d==0){    tA.copy(y>>5,cb,bA);    tB.copy(x>>5,cb,bB);  }  if(f[o].d==1){    y=n-y+1;    tA.copy(y>>5,cb,brA);    tB.copy(x>>5,cb,bB);  }  if(f[o].d==2){    x=m-x+1;    y=n-y+1;    tA.copy(y>>5,cb,brA);    tB.copy(x>>5,cb,brB);  }  if(f[o].d==3){    x=m-x+1;    tA.copy(y>>5,cb,bA);    tB.copy(x>>5,cb,brB);  }  tB.shl(0,x);  tA.shl(0,y);  tA.And(0,t>>5,tB);  ans-=tA.count(0,t);}void work(int*A,int*B){  for(i=1;i<=n;i++)sa[i]=sa[i-1]+a[i],bA.set(i,a[i]),brA.set(n-i+1,a[i]);  for(i=1;i<=m;i++)sb[i]=sb[i-1]+b[i],bB.set(i,b[i]),brB.set(m-i+1,b[i]);  cnt=0;  for(i=1;i<m;i++){    cnt++;    f[cnt].sx=i,f[cnt].sy=1;    f[cnt].ex=m,f[cnt].ey=m-i+1;    if(f[cnt].ey>n)f[cnt].ey=n,f[cnt].ex=n-1+i;    f[cnt].w=B[m-i+2];    f[cnt].d=0;    makerev(++cnt);  }  for(i=2;i<n;i++){    cnt++;    f[cnt].sx=1,f[cnt].sy=i;    f[cnt].ex=m,f[cnt].ey=m-1+i;    if(f[cnt].ey>n)f[cnt].ey=n,f[cnt].ex=n-i+1;    f[cnt].w=B[m+i];    f[cnt].d=0;    makerev(++cnt);  }  for(i=2;i<=m;i++){    cnt++;    f[cnt].sx=i,f[cnt].sy=1;    f[cnt].ex=1,f[cnt].ey=i;    if(f[cnt].ey>n)f[cnt].ey=n,f[cnt].ex=i+1-n;    f[cnt].w=A[i+1];    f[cnt].d=3;    makerev(++cnt);  }  for(i=2;i<n;i++){    cnt++;    f[cnt].sx=m,f[cnt].sy=i;    f[cnt].ex=1,f[cnt].ey=m+i-1;    if(f[cnt].ey>n)f[cnt].ey=n,f[cnt].ex=m+i-n;    f[cnt].w=A[i+m];    f[cnt].d=3;    makerev(++cnt);  }  for(i=1;i<=cnt;i++){    f[i].len=abs(f[i].sx-f[i].ex);    f[i].w-=check(f[i].ex,f[i].ey);    getid(f[i].sx,f[i].sy,f[i].d)=i;  }  for(i=1;i<=cnt;i++)f[i].nxt=getnxt(f[i].ex,f[i].ey,f[i].d);  cur=tot=0;  for(i=1;i<=cnt;i++)v[i]=0;  for(i=1;i<=cnt;i++)if(!v[i]){    st[++tot]=cur+1;    for(j=i;!v[j];j=f[j].nxt)v[q[++cur]=j]=tot;    en[tot]=cur;  }  for(i=1;i<=cnt;i++)sl[i]=sl[i-1]+f[q[i]].len,sw[i]=sw[i-1]+f[q[i]].w,pos[q[i]]=i;}}int main(){  for(i=1;i<65536;i++)g[i]=g[i>>1]+(i&1);  read(n),read(m);  scanf("%s%s",a+1,b+1);  for(i=1;i<=n;i++)a[i]-=‘0‘;  for(i=1;i<=m;i++)b[i]-=‘0‘;  read(ce);  for(i=1;i<=ce;i++)read(e[i].x),read(e[i].y),read(e[i].vx),read(e[i].vy),read(e[i].t);  FFT::work();  cb=(n>m?n:m)>>5;  for(i=1;i<=n;i++)Solve::a[i]=a[i];  for(i=1;i<=m;i++)Solve::b[i]=b[i];  Solve::work(ab,arb);  for(i=1;i<=ce;i++)if(e[i].vx==1&&e[i].vy==1)Solve::ask(e[i].x,e[i].y,e[i].t,i);  for(i=1;i<=n;i++)Solve::a[i]=a[n-i+1];  for(i=1;i<=m;i++)Solve::b[i]=b[i];  Solve::work(rab,rarb);  for(i=1;i<=ce;i++)if(e[i].vx==1&&e[i].vy==-1)Solve::ask(e[i].x,n-e[i].y+1,e[i].t,i);  for(i=1;i<=n;i++)Solve::a[i]=a[i];  for(i=1;i<=m;i++)Solve::b[i]=b[m-i+1];  Solve::work(arb,ab);  for(i=1;i<=ce;i++)if(e[i].vx==-1&&e[i].vy==1)Solve::ask(m-e[i].x+1,e[i].y,e[i].t,i);  for(i=1;i<=n;i++)Solve::a[i]=a[n-i+1];  for(i=1;i<=m;i++)Solve::b[i]=b[m-i+1];  Solve::work(rarb,rab);  for(i=1;i<=ce;i++)if(e[i].vx==-1&&e[i].vy==-1)Solve::ask(m-e[i].x+1,n-e[i].y+1,e[i].t,i);  for(i=1;i<=ce;i++)printf("%d\n",e[i].ans);  return 0;}

  

BZOJ3490 : Pa2011 Laser Pool