Description

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)

Input

第一行两个整数N、M,分别描述待处理的粒子运动轨迹的点列大小与数据库内的轨迹片断个数。接下来M行依次给出每个轨迹片断。每行先是一个正整数K,表示该轨迹片断点列的长度。然后2K个整数,依次描述点列中的K个点的横坐标与纵坐标。接下来一行2N个整数,依次描述待处理的粒子运动轨迹的点列中N个点的横坐标与纵坐标。

注:输入中的每条轨迹中任意相邻两点不会相同。

Output

应包含M行,依次给出每个片段在待处理运动轨迹中的出现次数。

Sample Input

3 2

2 17 0 10 1

3 0 0 1 0 1 -1

0 0 1 0 1 1

Sample Output

2

1

HINT

N, K ≤ 200 000,片段总长度 ≤ 1600000,输入中给出所有点坐标绝对值均不大于10 000。


考虑能够匹配,两个图形肯定是相似的

所以我们可以直接记录相邻两个边的长度比和夹角

然后炸精度……

换个方式记录,边长可以改为记录相邻两边的边长长度平方最简比(因为都是整点,平方后肯定是整数)

然后角度怎么记?可以用带符号的两边叉积点积最简比记录

翻转的话,把匹配串翻转一下再匹配就好了

注意判断翻转之后是否依然相似

然后AC自动机大力跑,Map存边即可,由于字符集很大,暴力跳Fail即可

/*program from Wolfycz*/
#include<map>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Fi first
#define Se second
#define MK make_pair
#define inf 0x7f7f7f7f
#define sqr(x) ((x)*(x))
#define For(T,i,x) for (T::iterator i=x.begin();i!=x.end();i++)
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef pair<int,int> pii;
typedef unsigned long long ull;
inline char gc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
int x=0,f=1; char ch=gc();
for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
inline int read(){
int x=0,f=1; char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
inline void print(int x){
if (x<0) putchar('-'),x=-x;
if (x>9) print(x/10);
putchar(x%10+'0');
}
const int N=2e5;
int Ans[N+10];
struct complex{
int x,y;
complex(int _x=0,int _y=0){x=_x,y=_y;}
int operator *(const complex &tis)const{return x*tis.y-y*tis.x;}
int operator /(const complex &tis)const{return x*tis.x+y*tis.y;}
complex operator +(const complex &tis)const{return complex(x+tis.x,y+tis.y);}
complex operator -(const complex &tis)const{return complex(x-tis.x,y-tis.y);}
void insert(int _x,int _y){x=_x,y=_y;}
};
struct node{
pii scl,rte;//scaling,rotate
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
pii work(pii tmp){
int d=max(1,gcd(abs(tmp.Fi),abs(tmp.Se)));
tmp.Fi/=d,tmp.Se/=d;
return tmp;
}
node(pii _scl=MK(0,0),pii _rte=MK(0,0)){scl=work(_scl),rte=work(_rte);}
void insert(pii _scl,pii _rte){scl=work(_scl),rte=work(_rte);}
bool operator <(const node &tis)const{return scl!=tis.scl?scl<tis.scl:rte<tis.rte;}
bool operator ==(const node &tis)const{return scl==tis.scl&&rte==tis.rte;}
bool operator !=(const node &tis)const{return !(*this==tis);}
};
struct S1{
map<node,int>trie[N+10];
int fail[N+10],cnt[N+10],tot,root;
vector<int>End[N+10];
S1(){tot=root=1;}
void insert(node *s,int n,int ID){
int p=root;
for (int i=1;i<=n;i++){
map<node,int>::iterator I=trie[p].find(s[i]);
if (I==trie[p].end()) I=trie[p].insert(map<node,int>::value_type(s[i],++tot)).Fi;
p=I->Se;
}
End[p].push_back(ID);
}
void make_fail(){
static int h[N+10];
int head=1,tail=1; h[1]=root;
for (;head<=tail;head++){
int Now=h[head];
for (map<node,int>::iterator it=trie[Now].begin();it!=trie[Now].end();it++){
int p=fail[Now];
while (p&&trie[p].find(it->Fi)==trie[p].end()) p=fail[p];
fail[it->Se]=p?trie[p].find(it->Fi)->Se:root;
h[++tail]=it->Se;
}
}
}
void work(node *s,int len){
int p=root;
for (int i=1;i<=len;i++){
while (p&&trie[p].find(s[i])==trie[p].end()) p=fail[p];
p=p?trie[p].find(s[i])->Se:root;
for (int x=p;x;x=fail[x]) cnt[x]++;
}
}
void updata(){
for (int i=1;i<=tot;i++)
For(vector<int>,I,End[i])
Ans[*I]+=cnt[i];
}
}AC;//Aho-Corasick automaton
int dis(pii x,pii y){return sqr(x.Fi-y.Fi)+sqr(x.Se-y.Se);}
int A[2][N+10],Len[N+10];
void init(node *R,int &len,int n){
len=0;
for (int i=2;i<n;i++){
pii Dis=MK(dis(MK(A[0][i+1],A[1][i+1]),MK(A[0][i],A[1][i])),dis(MK(A[0][i],A[1][i]),MK(A[0][i-1],A[1][i-1])));
complex x(A[0][i-1]-A[0][i],A[1][i-1]-A[1][i]),y(A[0][i+1]-A[0][i],A[1][i+1]-A[1][i]);
R[++len].insert(Dis,MK(x*y,x/y));
}
}
bool Dif[N+10];
node R[N+10],tmp[N+10];
int main(){
int n=read(),m=read(),len;
for (int i=1;i<=m;i++){
Len[i]=read();
for (int j=1;j<=Len[i];j++) A[0][j]=read(),A[1][j]=read();
if (Len[i]<3) continue;
init(R,len,Len[i]);
AC.insert(R,len,i);
for (int j=1;j<=Len[i];j++) A[1][j]=-A[1][j];
init(tmp,len,Len[i]);
for (int j=1;j<=len;j++) Dif[i]|=(R[j]!=tmp[j]);
Dif[i]^=1;
}
AC.make_fail();
for (int i=1;i<=n;i++) A[0][i]=read(),A[1][i]=read();
if (n>2){
init(R,len,n),AC.work(R,len);
for (int i=1;i<=n;i++) A[1][i]=-A[1][i];
init(R,len,n),AC.work(R,len);
}
AC.updata();
for (int i=1;i<=m;i++) printf("%d\n",Len[i]==1?n:Len[i]==2?n-1:Ans[i]>>Dif[i]);
return 0;
}

[ZJOI2008]无序运动Movement的更多相关文章

  1. bzoj1039: [ZJOI2008]无序运动Movement

    Description D博士对物理有着深入的研究,经典物理.天体物理.量子物理都有着以他的名字命名的定理.最近D博士着迷于研究粒子运动的无规则性.对圣经深信不疑的他相信,上帝创造的任何事物必然是有序 ...

  2. bzoj 1030-1039

    1030 JSOI2007 文本生成器 AC自动机加DP即可. 1031 JSOI2007 字符加密Cipher 后缀数组即可. 1032 JSOI2007 祖码Zuma 数据有问题. 设\(f(l, ...

  3. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  4. BZOJ练习记

    决定从头到尾干一波BZOJ!可能会写没几题就停下吧,但还是想学学新姿势啦. 1001. [BeiJing2006]狼抓兔子 即求 $(1, 1)$ 到 $(n, m)$ 的最小割.跑 dinic 即可 ...

  5. BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14302  Solved: 5779[Submit ...

  6. bzoj1036 [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 12646  Solved: 5085 [Subm ...

  7. BZOJ 1036: [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 14354  Solved: 5802 [Subm ...

  8. 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分

    [BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. ...

  9. 【BZOJ】【1040】【ZJOI2008】骑士

    树形DP/基环树DP 我掉坑掉了好多…… 这题图比较特殊,每个连通块都是一棵基环树(我一开始以为图是连通的了……sigh,我说为什么网上的题解都要累加ans……),那么对于一棵基环树,我们先dfs找到 ...

随机推荐

  1. Ubuntu下安装Android studio【转】

    本文转载自:http://blog.csdn.net/walleit/article/details/65696712 版权声明:本文为博主原创文章,未经博主允许不得转载. 一,软件准备 1. Lin ...

  2. LightOJ1236 —— 唯一分解定理 + 最小公倍数

    题目链接:https://vjudge.net/problem/LightOJ-1236 1236 - Pairs Forming LCM    PDF (English) Statistics Fo ...

  3. 整合kxmovie

    下载后发现kxmovie 直接运行是不通的,上面我们已经处理了ffmpeg部分的内容.当然了先处理ffmpeg部分.然后再复制kxmovie/kxmovie到项目中导入相应的文件. 编译报错:UIim ...

  4. codeforces 466C. Number of Ways 解题报告

    题目链接:http://codeforces.com/problemset/problem/466/C 题目意思:给出一个 n 个数的序列你,问通过将序列分成三段,使得每段的和都相等的分法有多少种. ...

  5. html5--5-8 绘制圆/弧

    html5--5-8 绘制圆/弧 学习要点 掌握绘制圆弧的方法 矩形的绘制方法 rect(x,y,w,h)创建一个矩形 strokeRect(x,y,w,hx,y,w,h) 绘制矩形(无填充) fil ...

  6. 从Inception v1,v2,v3,v4,RexNeXt到Xception再到MobileNets,ShuffleNet,MobileNetV2

    from:https://blog.csdn.net/qq_14845119/article/details/73648100 Inception v1的网络,主要提出了Inceptionmodule ...

  7. git bash使用端口转发连接服务器

    之前的配置是 url = user@xx.xx.xx.xx:/home/tutu/thelib/ww.git xx.xx.xx.xx是服务器的外网地址,其内网地址是zz.zz.zz.zz 但是现在服务 ...

  8. Numpy 小结

    Python 真火来学习一下,先来看一个库 NumPy.NumPy是Python语言的一个扩充程序库.支持高级大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库. 1. 读取文件 num ...

  9. ceph部署与问题

    一.基本情况:物理设备:4台惠普dl360,4个千兆网卡 4个1T盘操作系统统一为:CentOS 7.2.1511ceph版本:10.2.3ceph-deploy版本:1.5.36网络情况:192.1 ...

  10. 【网络爬虫】【java】微博爬虫(五):防止爬虫被墙的几个技巧(总结篇)

    爬虫的目的就是大规模地.长时间地获取数据,跟我们正常浏览器获取数据相比,虽然机理相差不大,但总是一个IP去爬网站,大规模集中对服务器访问,时间一长就有可能被拒绝.关于爬虫长时间爬取数据,可能会要求验证 ...