题意:
无序运动
【问题描述】
D博士对物理有着深入的研究,经典物理、天体物理、量子物理都有着以他的名字命名的定理。最近D博士着迷于研究粒子运动的无规则性。对圣经深信不疑的他相信,上帝创造的任何事物必然是有序的、有理可循的,而不是无规则的、混沌的。
经过长时间的研究,D博士找到了很多出现相当频繁的轨迹片断,他把这些轨迹片断储存在一个很大的数据库内。他需要你帮助他写一个程序,对于一个给出的粒子运动轨迹,统计数据库中每个轨迹片断的出现的次数。
为清楚起见,我们定义一个粒子的轨迹为二维平面上的一个点列(P1, P2, … PN)。点列P的一个子列[i, j]定义为P中一段连续的子序列(Pi, Pi+1, … Pj)。点列P的一个子列[u, v]被称为点列Q = (Q1, Q2 … Qv-u+1)在P中的一次出现,当且仅当Q经过有限次的平移、旋转、翻转、放缩之后得到Q’满足Q’k = Pu+k-1(k = 1 … u – v + 1)。
对平面X-Y进行四种操作的解释 | |
平移 | 设平移向量为(dx, dy),则任意点(x,y)平移后的结果为(x+dx, y+dy) |
旋转 | 设旋转角为t,则任意点(x,y)旋转后的结果为 (x cos t – y sin t, x sin t + y cos t) |
翻转 | 任意点(x,y) 翻转后的结果为(x, -y) |
放缩 | 设放缩比例为p (p ≠ 0),则任意点(x,y)放缩后的结果为(px, py) |
【输入文件】
输入文件movement.in第一行两个整数N、M,分别描述待处理的粒子运动轨迹的点列大小与数据库内的轨迹片断个数。
接下来M行依次给出每个轨迹片断。每行先是一个正整数K,表示该轨迹片断点列的长度。然后2K个整数,依次描述点列中的K个点的横坐标与纵坐标。
接下来一行2N个整数,依次描述待处理的粒子运动轨迹的点列中N个点的横坐标与纵坐标。
注:输入中的每条轨迹中任意相邻两点不会相同。
【输出文件】
输出文件movement.out应包含M行,依次给出每个片段在待处理运动轨迹中的出现次数。
这道题网上所有的数据和标程都是错的!
思路:AC自动机
每个点列 记三组特征值 两两边比 每个角的sin,cosn的值
AC自动机的字母个数比较多 用map
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<cstdio> 5 #include<map> 6 #include<algorithm> 7 using namespace std; 8 #define MAXN 400000+100 9 #define EPS 1e-8 10 struct point 11 { 12 double x,y; 13 point() {} 14 point(double x0,double y0):x(x0),y(y0){} 15 }; 16 struct list 17 { 18 double sinn,cosn,edge; 19 }; 20 struct node 21 { 22 list name; 23 map<list,node*> next; 24 node *failink,*father; 25 int id; 26 bool end; 27 }; 28 node memo[MAXN]; 29 node *head; 30 node *f[MAXN][2],*Q[MAXN]; 31 int n,m,top=0,label=0; 32 int front,behind; 33 int ans[MAXN],ans1[MAXN]; 34 point b[MAXN],a[MAXN]; 35 list p[MAXN]; 36 int dblcmp(double x) 37 { 38 if(fabs(x)<EPS) return 0; 39 return (x>0) ? 1:-1; 40 } 41 point operator -(const point &A,const point &B) 42 { 43 return point(A.x-B.x,A.y-B.y); 44 } 45 double operator *(const point &A,const point &B) 46 { 47 return A.x*B.x+A.y*B.y; 48 } 49 bool operator <(list A,list B) 50 { 51 if(dblcmp(A.edge-B.edge)>0) return 0; 52 if(dblcmp(A.edge-B.edge)<0) return 1; 53 if(dblcmp(A.sinn-B.sinn)>0) return 0; 54 if(dblcmp(A.sinn-B.sinn)<0) return 1; 55 if(dblcmp(A.cosn-B.cosn)>0) return 0; 56 if(dblcmp(A.cosn-B.cosn)<0) return 1; 57 return 0; 58 } 59 double cross(point p1,point p2) 60 { 61 return p1.x*p2.y-p1.y*p2.x; 62 } 63 double dist(const point &A,const point &B) 64 { 65 return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)); 66 } 67 void insert(int num,int n,int multi) 68 { 69 node *t=head,*q; 70 for(int i=1;i<=n;i++) 71 { 72 list x=p[i]; 73 x.sinn=p[i].sinn*multi; 74 if(t->next[x]==NULL) 75 { 76 q=&memo[top++]; q->name=x; q->father=t; q->id=++label; t->next[x]=q; 77 } 78 t=t->next[x]; 79 } 80 if(multi==1) 81 f[num][0]=t; 82 else f[num][1]=t; 83 } 84 85 void make_list(int n,int num) 86 { 87 bool w=0; 88 for(int i=1;i<n-1;i++) 89 { 90 p[i].edge=dist(b[i+2],b[i+1])/dist(b[i+1],b[i]); 91 p[i].sinn=cross(b[i+2]-b[i+1],b[i+1]-b[i])/dist(b[i+2],b[i+1])/dist(b[i+1],b[i]); 92 p[i].cosn=(b[i+2]-b[i+1])*(b[i+1]-b[i])/dist(b[i+2],b[i+1])/dist(b[i+1],b[i]); 93 if(dblcmp(p[i].sinn)!=0) w=1; 94 } 95 insert(num,n-2,1); 96 if(w) insert(num,n-2,-1); 97 } 98 void set_failure_link() 99 { 100 node *p,*t; 101 Q[front=behind=1]=head; 102 map<list,node*>::iterator i; 103 while(front<=behind) 104 { 105 p=Q[front++]; 106 if(p->father==head) p->failink=head; 107 else if(p!=head) 108 { 109 list x=p->name; 110 for(t=p->father->failink;t!=NULL;t=t->failink) 111 { 112 if(t->next[x]!=NULL) 113 { 114 p->failink=t->next[x]; break; 115 } 116 else if(t==head) 117 { 118 p->failink=t; break; 119 } 120 } 121 } 122 for(i=p->next.begin();i!=p->next.end();i++) 123 Q[++behind]=i->second; 124 } 125 } 126 void search() 127 { 128 int i=1; 129 node *t; 130 list x; 131 t=head; 132 while(i<=n) 133 { 134 x=p[i]; 135 if(t->next[x]==NULL) 136 { 137 if(t==head) i++; 138 else t=t->failink; 139 continue; 140 } 141 else t=t->next[x], i++; 142 ans[t->id]++; 143 } 144 } 145 void compensate() 146 { 147 for(int i=behind;i>0;i--) 148 ans[Q[i]->failink->id]+=ans[Q[i]->id]; 149 } 150 int main() 151 { 152 freopen("movement.in","r",stdin); 153 freopen("movement.out","w",stdout); 154 memset(f,0,sizeof(f)); 155 memset(ans,0,sizeof(ans)); 156 head=&memo[top++]; head->id=0; head->failink=head; 157 scanf("%d%d",&n,&m); 158 int i,j,k; 159 for(i=1;i<=m;i++) 160 { 161 scanf("%d",&k); 162 for(j=1;j<=k;j++) 163 scanf("%lf%lf",&b[j].x,&b[j].y); 164 if(k<=2) ans1[i]=n-k+1; 165 else make_list(k,i); 166 } 167 set_failure_link(); 168 for(i=1;i<=n;i++) 169 scanf("%lf%lf",&a[i].x,&a[i].y); 170 for(int i=1;i<n-1;i++) 171 { 172 p[i].edge=dist(a[i+2],a[i+1])/dist(a[i+1],a[i]); 173 p[i].sinn=cross(a[i+2]-a[i+1],a[i+1]-a[i])/dist(a[i+2],a[i+1])/dist(a[i+1],a[i]); 174 p[i].cosn=(a[i+2]-a[i+1])*(a[i+1]-a[i])/dist(a[i+2],a[i+1])/dist(a[i+1],a[i]); 175 } 176 n=n-2; 177 search(); 178 compensate(); 179 for(i=1;i<=m;i++) 180 { 181 if(f[i][0]==NULL) printf("%d\n",ans1[i]); 182 else 183 { 184 if(f[i][1]!=NULL) 185 printf("%d\n",ans[f[i][0]->id]+ans[f[i][1]->id]); 186 else printf("%d\n",ans[f[i][0]->id]); 187 } 188 } 189 return 0; 190 }