[2020.11.14提高组模拟] 鬼渊传说(village)

GMOJ​ 6862.鬼渊传说

一道由不会证的结论 + 十分繁琐 \(code\) 组成的题,改了一个晚上 + 半个早上......

差评!

\(Solution\)

首先由 欧拉公式 (%%%LZA):\(\text{n + r - m = 2}\),其中 \(n\) 为点数,\(r\) 为面数(包括整个图之外的面), \(m\) 为边数。

若不存在空腔,则 \(r =\) 四元环个数 \(+ 1\),(将四元环看成一个面),综上得:\(n +\) 四元环个数 \(- m = 1\)

那么不考虑空腔的话,可以枚举 \(O(n^3)\) 上下右边界,将 \(n\)\(m\)、四元环个数分别前缀和预处理好,用一个桶 \(O(1)\) 查询合法左边界个数即可。前缀和时需注意横竖边,为避免繁琐细节可以分为横、竖边分别前缀和,但是依旧很繁琐好吗

若一个矩形包含空腔,那么其向任意方向扩展后也依旧包含空腔,注意空腔个数上限 \(n^2\),所以可以预处理出所有空腔,对于空腔所在的最小的子矩形 \((x1, y1, x2, y2)\),若上界 \(i < x1\),那么在 \((x2 + 1, y2 + 1)\) 打上 \(y1 - 1\) 的限制,同样 \(O(n^2)\),最后记得下传(\((x, y) \rightarrow (x + 1, y)\)),指针 + 桶维护即可。

时间复杂度 \(O(n ^ 3)\)

\(Code\)

丑的心态很爆炸

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define N 301
#define M 90001
#define inf 1000000

#define fo(i, x, y) for(int i = x; i <= y; i ++)

struct Arr {
    int x, y;

    bool operator == (const Arr& a) {
        return x == a.x && y == a.y;
    }
};

struct Mat {
    int x1, y1, x2, y2, fx, fy;

    void Insert(int x, int y) { x1 = x2 = fx = x, y1 = y2 = fy = y; }

    Arr operator = (const Arr& a) {
        return (Arr) { fx = a.x, fy = a.y };
    }

    void operator += (const Mat &a) {
        x1 = min(x1, a.x1), y1 = min(y1, a.y1);
        x2 = max(x2, a.x2), y2 = max(y2, a.y2);
    }
} p[N + 1][N + 1];

struct Mat1 {
    int x1, y1, x2, y2;
    void operator = (const Mat& a) {
        x1 = a.x1, y1 = a.y1, x2 = a.x2, y2 = a.y2;
    }
} c[M + 1];

char ch[N + 1][N + 1];

int fn[N + 1][N + 1], fm[N + 1][N + 1], fr[N + 1][N + 1], a[N + 1][N + 1], gm[N + 1][N + 1];

int n, m, tot = 0;

Arr Getf(int x, int y) { return (x == p[x][y].fx && y == p[x][y].fy) ? (Arr) { x, y } : p[x][y] = Getf(p[x][y].fx, p[x][y].fy); }

void Merge(int x1, int y1, int x2, int y2) {
    Arr u = Getf(x1, y1), v = Getf(x2, y2);
    if (u == v) return;
    p[u.x][u.y] += p[v.x][v.y];
    p[v.x][v.y].fx = u.x, p[v.x][v.y].fy = u.y;
}

void Init() {
    fo(i, 1, n) fo(j, 1, m) a[i][j] = ch[i][j] - 48;
    fo(i, 1, n) fo(j, 1, m)
        fn[i][j] = fn[i - 1][j] + fn[i][j - 1] - fn[i - 1][j - 1] + a[i][j];
    fo(i, 1, n) fo(j, 1, m)
        fm[i][j] = fm[i - 1][j] + fm[i][j - 1] - fm[i - 1][j - 1] + (a[i][j] & a[i][j - 1]);
    fo(i, 1, n) fo(j, 1, m)
        fr[i][j] = fr[i - 1][j] + fr[i][j - 1] - fr[i - 1][j - 1] + (a[i][j] & a[i - 1][j] & a[i][j - 1] & a[i - 1][j - 1]);
    fo(i, 1, n) fo(j, 1, m)
        gm[i][j] = gm[i - 1][j] + gm[i][j - 1] - gm[i - 1][j - 1] + (a[i][j] & a[i - 1][j]);
    fo(i, 1, n) fo(j, 1, m) if (! a[i][j]) {
        p[i][j].Insert(i, j);
        if (j > 1 && ! a[i][j - 1])
            Merge(i, j - 1, i, j);
        if (i > 1 && ! a[i - 1][j])
            Merge(i - 1, j, i, j);
    }
    fo(i, 1, n) fo(j, 1, m)
        if ((Arr) { i, j } == Getf(i, j))
        	c[ ++ tot ] = p[i][j];
}

int s[N + 1][N + 1], h[inf << 5];

#define f1(j, k) (fn[j][k] + fr[j][k + 1] - fm[j][k + 1] - gm[j][k])
#define f2(i, k) (fn[i][k] + fr[i + 1][k] - gm[i + 1][k] - fm[i][k])
#define f3(i, j) (fn[i - 1][j - 1] + fr[i][j] - (fm[i - 1][j] + gm[i][j - 1]))
#define f(i, j) (fn[i][j] + fr[i][j] - fm[i][j] - gm[i][j])

int main() {
    freopen("village.in", "r", stdin);
    freopen("village.out", "w", stdout);

    scanf("%d %d\n", &n, &m);
    fo(i, 1, n) scanf("%s\n", ch[i] + 1);

    Init();

    int ans = 0;
    fo(i, 1, n) {
        fo(j, 0, n) fo(k, 0, m) s[j][k] = -1;
        fo(j, 1, tot) if (i < c[j].x1)
            s[c[j].x2 + 1][c[j].y2 + 1] = max(c[j].y1 - 1, s[c[j].x2 + 1][c[j].y2 + 1]);
        fo(k, 1, m) fo(j, 1, n) s[j][k] = max(s[j][k], s[j - 1][k]);
        fo(j, i, n) {
            int l = 0;
            fo(k, 0, m) {
                if (k) {
                    while (l < s[j][k] && l <= k)
                        -- h[f3(i, l + 1) - f1(j, l) + inf], ++ l;
                    ans += h[1 - (f(j, k) - f2(i - 1, k)) + inf];
                }
                ++ h[f3(i, k + 1) - f1(j, k) + inf];
            }
            while (l <= m)
                -- h[f3(i, l + 1) - f1(j, l) + inf], ++ l;
        }
    }
    printf("%d\n", ans);

    return 0;
}

posted @ 2020-11-15 09:35  buzzhou  阅读(193)  评论(0编辑  收藏  举报