BZOJ 1039. [ZJOI2008] disorderly movement Movement

 

Translation, rotation, scaling has no effect on two similar triangles, then n-$ $ a length of track can be described as $ n-2 $ triangles, each triangle on the use of the long sides of adjacent described, have to add in the first two segments clockwise or counterclockwise first segment, because if we do not turn this effect will be brought about not flipping, then it becomes a string matches. However, due to the large character set, starting a map to keep the edge. Then flip it and do it again.
If a track collinear, then flipped over and he will be re-counted, so divided by $ 2 $.
If a track length of less than $ 3 $, he will be able to match all of equal length of the substring.

#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

 

Guess you like

Origin www.cnblogs.com/Mrzdtz220/p/12233251.html