bzoj1039 [ZJOI2008]无序运动Movement AC自动机 计算几何
来源:互联网 发布:算法电子书 编辑:程序博客网 时间:2024/05/15 23:47
对于平移,旋转,放缩,由于任意相邻两线段呈夹角不变,长度比例不变。因此只需要判断相邻两线段长度比例和夹角不变。
夹角可以用叉积和点积的比值以及符号确定。
注意必须保留两个符号。
然后可以用AC自动机计算,每个点的答案是这个点fail树子树中的点被长串经过的次数和。
对于翻转操作只需把长的串翻转再做一遍。
注意判断翻转不变的串和长度小于3的串。
#include <bits/stdc++.h>using namespace std;#define N 200010#define M 1600010int n,m,cnt,tot;int len[M],fail[M],en[M],q[M],ans[M],num[M];bool one[M];map<int,int>ch[M];map<int,int>::iterator it; char getc(){ static const int LEN = 4096; static char buf[LEN],*S=buf,*T=buf; if(S == T) { T = (S=buf)+fread(buf,1,LEN,stdin); if(S == T)return EOF; } return *S++;}int read(){ static char ch; static int D; int tp=0; while(!isdigit(ch=getc())) if(ch=='-')tp=1; for(D=ch-'0'; isdigit(ch=getc());) D=(D<<3)+(D<<1)+(ch-'0'); return tp ? -D:D;}struct poi{ int x,y; poi(){} poi(int x,int y):x(x),y(y){} friend int operator * (const poi &r1,const poi &r2) {return r1.x*r2.x+r1.y*r2.y;} friend int operator ^ (const poi &r1,const poi &r2) {return r1.x*r2.y-r2.x*r1.y;} friend poi operator - (const poi &r1,const poi &r2) {return poi(r1.x-r2.x,r1.y-r2.y);} int len(){return x*x+y*y;}}a[M],b[N];struct node{ int v1,v2,v3,v4; node(){} node(int r1,int r2,int r3,int r4) { int t=abs(__gcd(r1,r2)); v1=r1/t;v2=r2/t;v3=r3;v4=r4; if(!r3)v4= r4<0 ? -1:1; else if(!r4)v3= r3<0 ? -1:1; else t=abs(__gcd(r3,r4)),v3/=t,v4/=t; } friend bool operator < (const node &r1,const node &r2) { return r1.v1==r2.v1 ? (r1.v2==r2.v2 ? (r1.v3==r2.v3 ? r1.v4<r2.v4:r1.v3<r2.v3):r1.v2<r2.v2):r1.v1<r2.v1; } friend bool operator != (const node &r1,const node &r2) {return r1.v1!=r2.v1||r1.v2!=r2.v2||r1.v3!=r2.v3||r1.v4!=r2.v4;}}st[M],s[N],v[M];int get(node x){ int t=lower_bound(st+1,st+1+cnt,x)-st; if(st[t]!=x)return 0; return t;}void match(){ int h,r;q[h=r=1]=1; while(h<=r) { int t=q[h++]; for(it=ch[t].begin();it!=ch[t].end();++it) { int t1=fail[t]; while(t1&&!ch[t1].count((*it).first)) t1=fail[t1]; fail[(*it).second]=t1 ? ch[t1][(*it).first]:1; q[++r]=(*it).second; } }}void calc(){ memset(num,0,sizeof(num)); for(int now=1,i=2;i<n;i++) { int t=get(s[i]); while(now&&!ch[now].count(t)) now=fail[now]; now=now ? ch[now][t]:1; num[now]++; } for(int i=tot;i>=1;i--) num[fail[q[i]]]+=num[q[i]]; for(int i=1;i<=m;i++) if(len[i]>2) ans[i]+=num[en[i]];}int main(){ //freopen("tt.in","r",stdin); n=read();m=read(); for(int i=1,K;i<=m;i++) { len[i]=read(); for(int j=1;j<=len[i];j++) a[j].x=read(),a[j].y=read(); if(len[i]<=2)continue; one[i]=1; for(int j=2;j<len[i];j++) { poi p1=a[j]-a[j-1],p2=a[j+1]-a[j]; v[++cnt]=st[cnt]=node(p1.len(),p2.len(),p1*p2,p1^p2); if(p1^p2)one[i]=0; } } sort(st+1,st+1+cnt); for(int i=1;i<=n;i++) b[i].x=read(),b[i].y=read(); tot=1;fail[1]=0; for(int i=1,cnt=1;i<=m;i++) if(len[i]>2) { int now=1; for(int j=0;j<len[i]-2;j++,cnt++) { int t=get(v[cnt]); if(!ch[now].count(t)) ch[now][t]=++tot; now=ch[now][t]; } en[i]=now; } match(); for(int i=2;i<n;i++) { poi p1=b[i]-b[i-1],p2=b[i+1]-b[i]; s[i]=node(p1.len(),p2.len(),p1*p2,p1^p2); } calc(); for(int i=2;i<n;i++)s[i].v4=-s[i].v4; calc(); for(int i=1;i<=m;i++) { if(len[i]<=2)printf("%d\n",n-len[i]+1); else { if(one[i])ans[i]/=2; printf("%d\n",ans[i]); } } return 0;}
0 0
- bzoj1039 [ZJOI2008]无序运动Movement AC自动机 计算几何
- 【计算几何】zjoi2008 risk
- bzoj1094 粒子运动 计算几何
- 【半平面交】【计算几何】[BZOJ1038][ZJOI2008]瞭望塔
- 【模拟】【计算几何】[ZJOI2008][HYSBZ/BZOJ1033]杀蚂蚁antbuster
- HYSBZ/BZOJ 1038 [ZJOI2008] 瞭望塔 - 计算几何
- BZOJ 1094 ZJOI2007 粒子运动 计算几何
- AC自动机...
- AC自动机
- AC 自动机
- AC自动机
- AC自动机
- ac自动机
- ac自动机
- AC自动机
- AC自动机
- AC自动机
- AC自动机
- C#的值参数 输出参数 引用参数
- 框架Fresco的使用
- WebStorm用法及快捷键
- Android提醒微技巧,你真的了解Dialog、Toast和Snackbar吗?
- 资源图与死锁定理的灵活运用
- bzoj1039 [ZJOI2008]无序运动Movement AC自动机 计算几何
- Linux常用命令
- Java利用JDom解析和传递XML格式数据
- 上传下载
- .Net web提交到后台中文乱码问题解决
- Android之Manifest文件
- 安装qt qmake 错误:could not find a Qt installation of ''
- IO流
- MPI—聚集函数MPI_Gather()