[ZJOI2008]无序运动Movement
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的更多相关文章
- bzoj1039: [ZJOI2008]无序运动Movement
Description D博士对物理有着深入的研究,经典物理.天体物理.量子物理都有着以他的名字命名的定理.最近D博士着迷于研究粒子运动的无规则性.对圣经深信不疑的他相信,上帝创造的任何事物必然是有序 ...
- bzoj 1030-1039
1030 JSOI2007 文本生成器 AC自动机加DP即可. 1031 JSOI2007 字符加密Cipher 后缀数组即可. 1032 JSOI2007 祖码Zuma 数据有问题. 设\(f(l, ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- BZOJ练习记
决定从头到尾干一波BZOJ!可能会写没几题就停下吧,但还是想学学新姿势啦. 1001. [BeiJing2006]狼抓兔子 即求 $(1, 1)$ 到 $(n, m)$ 的最小割.跑 dinic 即可 ...
- BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 14302 Solved: 5779[Submit ...
- bzoj1036 [ZJOI2008]树的统计Count
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MB Submit: 12646 Solved: 5085 [Subm ...
- BZOJ 1036: [ZJOI2008]树的统计Count
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MB Submit: 14354 Solved: 5802 [Subm ...
- 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分
[BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. ...
- 【BZOJ】【1040】【ZJOI2008】骑士
树形DP/基环树DP 我掉坑掉了好多…… 这题图比较特殊,每个连通块都是一棵基环树(我一开始以为图是连通的了……sigh,我说为什么网上的题解都要累加ans……),那么对于一棵基环树,我们先dfs找到 ...
随机推荐
- [NOIP2011提高组day1]-3-mayan游戏
3.Mayan 游戏 (mayan.cpp/c/pas) [问题描述] Mayan puzzle 是最近流行起来的一个游戏.游戏界面是一个 7行 5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即 ...
- [noi2002]M号机器人
3030年,Macsy正在火星部署一批机器人.第1秒,他把机器人1号运到了火星,机器人1号可以制造其他的机器人.第2秒,机器人1号造出了第一个机器人——机器人2号.第3秒,机器人1号造出了另一个机器人 ...
- CSS Overflow 属性清除浮动
清除浮动 设置overflow的一个更流行的用处是,说也奇怪,清除浮动.设置overflow并不会在该元素上清除浮动,它将清除自己(self-clear).意思就是,应用了overflow(auto或 ...
- 在jboss中部署可执行jar, deploy executable jar in jboss
首先,题目是个伪命题, jboss容器是不支持直接部署可执行jar包的,jar只会被加载当作lib对待.这里提供了一个小的变通方案. 今天我遇到个问题,把我们的项目中的监控模块独立成一个小项目部署,监 ...
- eclipse订制快捷键
步骤: 1.window-preference. 2.在(1)处输入keys,在(2)处输入命令的原来的快捷键,方便找到Binding,在(3)处输入自定义的快捷键.点击“apply and clos ...
- tomcat 启动增加参数
linux: JAVA_OPTS="$JAVA_OPTS -Dconfig.type=inte2 -Xms2048m -Xmx2048m -XX:PermSize=128m -XX:Max ...
- Java丨时间判断谁前谁后
直奔主题: String date_str1 = "2016-06-02 23:03:123"; String date_str2 = "2016-06-03 03:03 ...
- CodeForces960F:Pathwalks (主席树+DP)
You are given a directed graph with n nodes and m edges, with all edges having a certain weight. The ...
- CTSC2012 熟悉的文章
传送门 首先很容易想到对于所有的模式串建出广义后缀自动机,之后对于我们每一个要检查的文本串,先在SAM上跑,计算出来每一个位置能匹配到的最远的位置是多少.(就是当前点减去匹配长度) 之后--考虑DP- ...
- MTK OTG 流程
一.注册mt_usb驱动 kernel-3.18/drivers/misc/mediatek/usb20/mt6735/usb20.c static int __init usb20_init(voi ...