列表

详情


NC20475. [ZJOI2008]无序运动MOVEMENT

描述

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)

输入描述

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

输出描述

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

示例1

输入:

3 2
2 17 0 10 1
3 0 0 1 0 1 -1
0 0 1 0 1 1

输出:

2
1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 355ms, 内存消耗: 18004K, 提交时间: 2020-04-02 13:48:10

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+9;
int n,m,k,tot=0,fail[maxn],last[maxn],cnt[maxn],ans[maxn],tp[maxn];
struct point{
    int x,y;
    point operator - (const point &b){return point{x-b.x,y-b.y};}
    int operator * (const point &b) {return x*b.y-y*b.x;}
    int operator ^ (const point &b) {return x*b.x+y*b.y;}
}po[maxn];
struct node{
    int a,b,c,d;
    bool operator < (const node &x) const{
        if(a!=x.a) return a<x.a;
        if(b!=x.b) return b<x.b;
        if(c!=x.c) return c<x.c;
        return d<x.d;
    }
}s[maxn];
node change(point a,point b,point c)
{
    node an;
    an.a=(b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y);
    an.b=(c.x-b.x)*(c.x-b.x)+(c.y-b.y)*(c.y-b.y);
    an.c=(b-a)*(c-b);
    an.d=(b-a)^(c-b);
    int t=__gcd(an.a,an.b);
    if(t!=0) an.a/=t,an.b/=t;
    t=__gcd(abs(an.c),abs(an.d));
    if(t!=0) an.c/=t,an.d/=t;
    return an;
}
map<node,int> nex[maxn];
vector<int> ed[maxn];
#define iter map<node,int>::iterator
void ins(int len,int id)
{
    int now=0;
    for(int i=1;i<=len;i++)
    {
        iter it=nex[now].find(s[i]);
        if(it==nex[now].end()) now=nex[now][s[i]]=++tot;
        else now=it->second;
    }
    ed[now].push_back(id);
}
void build()
{
    queue<int> que;
    for(iter it=nex[0].begin();it!=nex[0].end();it++) que.push(it->second);
    while(!que.empty())
    {
        int now=que.front();
        que.pop();
        for(iter it=nex[now].begin();it!=nex[now].end();it++)
        {
            node a=it->first;
            int b=it->second,c=fail[now];
            while(c&&nex[c].find(a)==nex[c].end()) c=fail[c];
            if(nex[c].find(a)!=nex[c].end()) c=nex[c][a];
            fail[b]=c;
            last[b]=ed[c].empty()?last[c]:c;
            que.push(b);
        }
    }
}
void solve()
{
    int now=0;
    for(int i=1;i<=n-2;i++)
    {
        int x=now;
        while(x&&nex[x].find(s[i])==nex[x].end()) x=fail[x];
        if(nex[x].find(s[i])!=nex[x].end())
            x=nex[x][s[i]];
        now=x;
        for(;x;x=last[x]) cnt[x]++;
    }
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int flag=1;
        scanf("%d",&k);
        for(int j=1;j<=k;j++) scanf("%d %d",&po[j].x,&po[j].y);
        if(k<=2) 
        {ans[i]=n-1;continue;}
        for(int j=2;j<k;j++)
        {
            s[j-1]=change(po[j-1],po[j],po[j+1]);
            if(s[j-1].c) flag=0;
        }
        if(flag) tp[i]=1;
        ins(k-2,i);
    }
    build();
    for(int i=1;i<=n;i++) scanf("%d %d",&po[i].x,&po[i].y);
    for(int i=2;i<n;i++) s[i-1]=change(po[i-1],po[i],po[i+1]);
    solve();
    for(int i=1;i<=n;i++) po[i].x=-po[i].x;
    for(int i=2;i<n;i++) s[i-1]=change(po[i-1],po[i],po[i+1]);
    solve();
    for(int i=1;i<=tot;i++)
    {
        for(int j=0;j<ed[i].size();j++) ans[ed[i][j]]+=cnt[i];
    }
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]/(tp[i]+1));
    return 0;
}

C++ 解法, 执行用时: 106ms, 内存消耗: 87308K, 提交时间: 2021-05-21 16:54:03

#include<bits/stdc++.h>
const int N=1600007;
char buf[30000007],*ptr=buf-1;
int _(){
    int x=0,f=1,c=*++ptr;
    while(c<48)c=='-'&&(f=-1),c=*++ptr;
    while(c>47)x=x*10+c-48,c=*++ptr;
    return x*f;
}
int gcd(int a,int b){
    for(int c;b;c=a,a=b,b=c%b);
    return a;
}
int dis(int x,int y){
    return x*x+y*y;
}
int n,m,x[N],y[N],e[N],ans[N];
bool re[N];
struct tri{
    int a,b,c,d;
    tri(int w){
        int x1=x[w]-x[w-1],y1=y[w]-y[w-1],x2=x[w]-x[w+1],y2=y[w]-y[w+1];
        a=dis(x1,y1);
        b=dis(x2,y2);
        c=dis(x1-x2,y1-y2);
        int g=gcd(a,gcd(b,c));
        if(g>1)a/=g,b/=g,c/=g;
        d=x1*y2-x2*y1;
        d=d<0?-1:d>0;
    }
    bool operator<(tri w)const{
        return a!=w.a?a<w.a:b!=w.b?b<w.b:c!=w.c?c<w.c:d<w.d;
    }
};
std::map<tri,int>nx[N];
int p=1,fa[N],deg[N],t[N],q[N],ql=0,qr=0;
int main(){
    buf[fread(buf,1,sizeof(buf),stdin)]=0;
    n=_();m=_();
    for(int i=0;i<m;++i){
        int c=_();
        for(int j=0;j<c;++j){
            x[j]=_();y[j]=_();
        }
        if(c<3)ans[i]=n+1-c,re[i]=1;
        else{
            int w=1;
            for(int j=2;j<c;++j){
                tri t(j-1);
                if(t.d)re[i]=1;
                if(nx[w].find(t)==nx[w].end())nx[w][t]=++p;
                w=nx[w][t];
            }
            e[i]=w;
        }
    }
    ql=qr=0;q[++qr]=1;
    while(ql!=qr){
        int w=q[++ql];
        for(std::map<tri,int>::iterator it=nx[w].begin();it!=nx[w].end();++it){
            int u=it->second,v=fa[w];
            q[++qr]=u;
            while(v&&nx[v].find(it->first)==nx[v].end())v=fa[v];
            fa[u]=v?nx[v][it->first]:1;
        }
    }
    for(int i=0;i<n;++i){
        x[i]=_();y[i]=_();
    }
    int w=1;
    for(int i=2;i<n;++i){
        tri t(i-1);
        while(w&&nx[w].find(t)==nx[w].end())w=fa[w];
        w=w?nx[w][t]:1;
        ++::t[w];
    }
    for(int i=0;i<n;++i)y[i]=-y[i];
    w=1;
    for(int i=2;i<n;++i){
        tri t(i-1);
        while(w&&nx[w].find(t)==nx[w].end())w=fa[w];
        w=w?nx[w][t]:1;
        ++::t[w];
    }
    ql=qr=0;
    for(int i=1;i<=p;++i)++deg[fa[i]];
    for(int i=1;i<=p;++i)if(!deg[i])q[++qr]=i;
    deg[0]=0x3f3f3f3f;
    while(ql!=qr){
        int w=q[++ql],f=fa[w];
        t[f]+=t[w];
        if(!--deg[f])q[++qr]=f;
    }
    for(int i=0;i<m;++i)if(e[i])ans[i]=t[e[i]];
    for(int i=0;i<m;++i)printf("%d\n",re[i]?ans[i]:ans[i]>>1);
    return 0;
}

上一题