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


    GMOJ​ 6862.鬼渊传说

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

    差评!

    (Solution)

    首先由 欧拉公式 (%%%LZA):( ext{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) ightarrow (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, &m);
        fo(i, 1, n) scanf("%s
    ", 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
    ", ans);
    
        return 0;
    }
    
    
  • 相关阅读:
    SQlite数据库
    关于如何获取剪切板的多个图片处理
    aes 和 Md5 分析
    SIP消息
    getItemAt
    C++ map的方法
    C++ 解析Json
    CentOS 6.3安装配置LAMP服务器(Apache+PHP5+MySQL)
    阿里云服务器CentOS 5.7(64位)安装配置LAMP服务器(Apache+PHP5+MySQL)
    Apache虚拟主机(vhost)配置教程
  • 原文地址:https://www.cnblogs.com/zhouzj2004/p/13975752.html
Copyright © 2020-2023  润新知