ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BZOJ 1039. [ZJOI2008]无序运动Movement

2020-01-25 18:01:34  阅读:254  来源: 互联网

标签:rt node int 1039 mp ZJOI2008 fail vec BZOJ


 

平移、旋转、放缩对两个相似三角形没有影响,那么一个长度为 $n$ 的轨迹就可以描述为 $n-2$ 个三角形,每个三角形就用相邻两边长来描述,还得加上第二条线段在第一条线段的逆时针还是顺时针方向,因为如果不加这个就会出现翻不翻转带来的影响,然后就变成了字符串匹配了。不过由于字符集很大,得用 map 来存边。然后翻转一下再做一遍。
如果一个轨迹共线的话,翻转后他会被重新算一遍,所以要除以 $2$。
如果一个轨迹长度小于 $3$ 的话, 他就能匹配上所有长度相等的子串。

#include <bits/stdc++.h>

namespace IO {
    char buf[1 << 21], buf2[1 << 21], a[20], *p1 = buf, *p2 = buf, hh = '\n';
    int p, p3 = -1;
    void read() {}
    void print() {}
    inline int getc() {
        return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
    }
    inline void flush() {
        fwrite(buf2, 1, p3 + 1, stdout), p3 = -1;
    }
    template <typename T, typename... T2>
    inline void read(T &x, T2 &... oth) {
        T f = 1; x = 0;
        char ch = getc();
        while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getc(); }
        while (isdigit(ch)) { x = x * 10 + ch - 48; ch = getc(); }
        x *= f;
        read(oth...);
    }
    template <typename T, typename... T2>
    inline void print(T x, T2... oth) {
        if (p3 > 1 << 20) flush();
        if (x < 0) buf2[++p3] = 45, x = -x;
        do {
            a[++p] = x % 10 + 48;
        } while (x /= 10);
        do {
            buf2[++p3] = a[p];
        } while (--p);
        buf2[++p3] = hh;
        print(oth...);
    }
}

struct P {
    int x, y;
    void read() { IO::read(x, y); }
    void print() { printf("%d %d\n", x, y); }
    P() {}
    P(int x, int y): x(x), y(y) {}
    P operator + (const P &p) const { return P(x + p.x, y + p.y); }
    P operator - (const P &p) const { return P(x - p.x, y - p.y); }
    int det(const P &p) const { return x * p.y - y * p.x; }
    int abs2() { return x * x + y * y; }
};

struct Node {
    int a, b, c, dir;
    bool operator < (const Node &p) const {
        if (a != p.a) return a < p.a;
        if (b != p.b) return b < p.b;
        if (c != p.c) return c < p.c;
        return dir < p.dir;
    }
    bool operator == (const Node &p) const {
        return !(*this < p) && !(p < *this);
    }
};

const int N = 2e5 + 7;
int n, m, par[N], tol, ans[N];
std::vector<P> point[N], all;
std::vector<int> flag[N];
std::map<Node, int> mp[N];

int gcd(int a, int b) {
    while (b) {
        a %= b;
        std::swap(a, b);
    }
    return a;
}

Node getnode(const P &A, const P &B, const P &C) {
    int lena = (B - A).abs2(), lenb = (B - C).abs2(), lenc = (A - C).abs2();
    int g = gcd(lena, gcd(lenb, lenc));
    lena /= g, lenb /= g, lenc /= g;
    int crs = 0;
    if ((B - A).det(C - B) > 0) crs = 1;
    else if ((B - A).det(C - B) < 0) crs = -1;
    return {lena, lenb, lenc, crs};
}


void done(std::vector<P> vec, int id) {
    if (vec.size() < 3) {
        ans[id] = n - vec.size() + 1;
        return;
    }
    par[id] = 1;
    int rt = 0;
    for (int i = 0; i < vec.size() - 2; i++) {
        Node o = getnode(vec[i], vec[i + 1], vec[i + 2]);
        if (o.dir) par[id] = 0;
        auto it = mp[rt].find(o);
        if (it == mp[rt].end()) {
            mp[rt][o] = ++tol;
            rt = tol;
        } else {
            rt = it->second;
        }
    }
    flag[rt].push_back(id);
}

int fail[N], last[N], cnt[N];

void build() {
    std::queue<int> que;
    for (auto it: mp[0])
        que.push(it.second);
    while (!que.empty()) {
        int u = que.front(); que.pop();
        for (auto it: mp[u]) {
            Node cur_node = it.first;
            int f = fail[u], v = it.second;
            for (; f && mp[f].find(cur_node) == mp[f].end(); f = fail[f]);
            if (mp[f].find(cur_node) != mp[f].end())
                f = mp[f][cur_node];
            fail[v] = f;
            last[v] = flag[fail[v]].empty() ? last[fail[v]] : fail[v];
            que.push(v);
        }
    }
}

void solve(const std::vector<P> &vec) {
    int rt = 0;
    for (int i = 0; i < n - 2; i++) {
        Node node = getnode(vec[i], vec[i + 1], vec[i + 2]);
        for (; rt && mp[rt].find(node) == mp[rt].end(); rt = fail[rt]);
        if (mp[rt].find(node) != mp[rt].end())
            rt = mp[rt][node];
        for (int j = rt; j; j = last[j])
            ++cnt[j];
    }
}

int main() {
    IO::read(n, m);
    for (int i = 1; i <= m; i++) {
        int k;
        IO::read(k);
        point[i].resize(k);
        for (int j = 0; j < k; j++) 
            point[i][j].read();
        done(point[i], i);
    }
    build();
    all.resize(n);
    for (int i = 0; i < n; i++)
        all[i].read();
    solve(all);
    for (int i = 0; i < n; i++)
        all[i].y *= -1;
    solve(all);
    for (int i = 1; i <= tol; i++)
        for (int u: flag[i])
            ans[u] += cnt[i] / (par[u] + 1);
    for (int i = 1; i <= m; i++)
        IO::print(ans[i]);
    IO::flush();
    return 0;
}
View Code

 

标签:rt,node,int,1039,mp,ZJOI2008,fail,vec,BZOJ
来源: https://www.cnblogs.com/Mrzdtz220/p/12233251.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有