• 自嗨测试赛4



    在出题组,没啥参考价值。出题的时候3个题一个都不会

    A 简单的树叶

    题目大意 : 每个点规定是儿子的值的min或max,k个叶子结点的值可以是1到k,每个数只能用一次,求根节点的最大值

    • 原题:CF1153D Serval and Rooted Tree

    • f[x]表示可决定x点值大小的最少有几个,因为点越少,值就可以越大

    • 当取max时f[x]是子节点的f值的min

    • 当去min时f[x]是子节点的f值的和

    Code

    Show Code
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    const int N = 3e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
        return x * f;
    }
    
    struct Edge {
        int n, t;
    }e[N];
    int h[N], edc;
    
    void Add(int x, int y) {
        e[++edc] = (Edge) {h[x], y}; h[x] = edc;
    }
    
    bool v[N];
    int n, m;
    
    int Dfs(int x) {
        if (!h[x]) return 1;
        int w = v[x] ? n : 0;
        for (int i = h[x]; i; i = e[i].n)
            w = v[x] ? min(w, Dfs(e[i].t)) : w + Dfs(e[i].t);
        return w;
    }
    
    int main() {
        freopen("leaf.in", "r", stdin);
        freopen("leaf.out", "w", stdout);
        n = read();
        for (int i = 1; i <= n; ++i)
            v[i] = read();
        for (int i = 2; i <= n; ++i)
            Add(read(), i);
        for (int i = 1; i <= n; ++i)
            if (!h[i]) m++;
        printf("%d
    ", m - Dfs(1) + 1);
        return 0;
    }
    

    B 老姚的服装

    题目大意 : 给一个二维画布,在画布上规定区间找到面积最大的图案

    • 原题:CF1301E Nanosoft,注意本题颜色与原题不一样

    • 二维前缀和可以找到以每个点为左上角的图形,预处理每个长度的图形的出现情况的前缀和,回答的时候二分一个长度就好了

    Code

    Show Code
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    const int N = 505;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
        return x * f;
    }
    
    char c[N];
    int n, m, q;
    
    struct Node {
        int s[N][N];
    
        void Init() {
            for (int i = 1; i <= n; ++i)
                for (int j = 1; j <= m; ++j)
                    s[i][j] += s[i][j-1] + s[i-1][j] - s[i-1][j-1];
        }
    
        int Cal(int i, int j, int k, int l) {
            i--, j--;
            if (i + k > n || j + l > m) return -1;
            return s[i+k][j+l] - s[i][j+l] - s[i+k][j] + s[i][j];
        }
    }s[4], f[N/2];
    
    int main() {
        freopen("clothes.in", "r", stdin);
        freopen("clothes.out", "w", stdout);
        n = read(); m = read(); q = read();
        for (int i = 1; i <= n; ++i) {
            scanf("%s", c + 1);
            for (int j = 1; j <= m; ++j)
                s[c[j] == 'B' ? 0 : c[j] == 'W' ? 1 : c[j] == 'P' ? 2 : 3].s[i][j]++;
        }
        s[0].Init(); s[1].Init(); s[2].Init(); s[3].Init();
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                for (int k = 1, lim = min(n - i, m - j) + 1 >> 1; k <= lim && s[0].Cal(i, j, k, k) == k * k; ++k) 
                    if (s[1].Cal(i, j + k, k, k) == k * k && s[2].Cal(i + k, j, k, k) == k * k && s[3].Cal(i + k, j + k, k, k) == k * k)
                        f[k].s[i][j]++, k = lim; 
        for (int k = min(n, m) >> 1; k >= 1; --k) f[k].Init();
        while (q--) {
            int lx = read(), ly = read(), rx = read(), ry = read();
            int l = 0, r = min(rx -= lx - 2, ry -= ly - 2) >> 1;
            while (l < r) {
                int mid = l + r + 1 >> 1;
                if (f[mid].Cal(lx, ly, rx - mid * 2, ry - mid * 2)) l = mid;
                else r = mid - 1;
            }
            printf("%d
    ", 4 * l * l);
        }
        return 0;
    }
    

    C Shawk 的游戏

    题目大意 : 问能否在两行里放一棵树,满足树边不相交

    • 原题是 CF573C Bear and Drawing,拉过来之后改成了多测

    • 网上的题解挺难懂,我和 HISKrrr 研究了一下午一点儿也没懂,最后发现挺简单,凯爹应该可以一眼切

    解法一

    • 仔细观察样例的第二组数据,会发现只要n比13小那是不可能放不上去的,所以大力puts("Yes")就有10分了

    解法二

    • 发现合法的方案一定可以找出一条主干放到第一行,然后剩下的可以在第二行放下,

    • 所以n2枚举主干是哪条链,然后主干下面一级的点最多有3个度,剩下的只能有2个度,Dfs一遍判断一下即可

    • 放个代码,时间复杂度 (O(n^3)),期望30分

    Show Code
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    const int N = 1e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
        return x * f;
    }
    
    struct Edge {
        int n, t;
    }e[N*2];
    int h[N], edc, d[N];
    
    void Add(int x, int y) {
        e[++edc] = (Edge) {h[x], y}; h[x] = edc; d[x]++;
    }
    
    bool v[N], g;
    int n, a[N], cnt;
    
    bool Dfs(int x, int fa, int k) {
        if (d[x] > k) return 0;
        int ans = 1;
        for (int i = h[x], y; i && ans; i = e[i].n)
            if ((y = e[i].t) != fa && !v[y]) ans = Dfs(y, x, 2);
        return ans;
    }
    
    void Solve() {
        int ans = 1;
        for (int x = 1; x <= cnt && ans; ++x)
            for (int i = h[a[x]], y; i && ans; i = e[i].n)
                if (!v[y=e[i].t]) ans = Dfs(y, 0, 3);
        if (ans) g = 1;
    }
    
    void Dfs(int x, int fa) {
        a[++cnt] = x; v[x] = 1;
        Solve();
        for (int i = h[x], y; i && !g; i = e[i].n)
            if ((y = e[i].t) != fa) Dfs(y, x);
        cnt--; v[x] = 0;
    }
    
    int main() {
        while (scanf("%d", &n) == 1) {
            memset(d + 1, 0, n * 4);
            memset(h + 1, 0, n * 4);
            g = 0; edc = 0;
            for (int i = 1; i < n; ++i) {
                int x = read(), y = read();
                Add(x, y); Add(y, x);
            }
            for (int i = 1; i <= n && !g; ++i) Dfs(i, 0);
            puts(g ? "Yes" : "No");
        }
        return 0;
    }
    
    • 其实可以优化到叶子节点个数的平方乘n,但是叶子节点少了的话就大概率是Yes了(其实是不知道该怎么分配数据和分数了)

    解法三

    • 可以枚举根结点,然后在子节点中枚举两个节点作为主干上的点,其他的节点放第二行,根据第几级儿子判断度数是否合适

    • 其他主干上的点只能向一侧延伸一个主干上的点,枚举这个点,其他节点放第二行,判断同上

    • 由于我太菜了,复杂度分析不出来,n=100的数据就让它过了,想卡的话可能是度数弄多一点

    • 参考代码

    Show Code
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    const int N = 1e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
        return x * f;
    }
    
    struct Edge {
        int n, t;
    }e[N*2];
    int h[N], edc, d[N];
    
    void Add(int x, int y) {
        e[++edc] = (Edge) {h[x], y}; h[x] = edc; d[x]++;
    }
    
    bool g;
    int n;
    
    bool Solve(int x, int fa, int k) {
        if (d[x] == 1) return 1;
        if (k && d[x] - 1 > k) return 0;
        if (!k) {
            for (int i = h[x]; i; i = e[i].n) {
                if (e[i].t == fa) continue;
                bool ans = Solve(e[i].t, x, k);
                for (int j = h[x]; j && ans; j = e[j].n)
                    if (e[j].t != fa && i != j) ans = Solve(e[j].t, x, 2);
                if (ans) return 1;
            }
            return 0;
        }
        else {
            for (int i = h[x]; i; i = e[i].n)
                if (e[i].t != fa && !Solve(e[i].t, x, 1)) return 0;
            return 1;
        }
    }
    
    int main() {
        while (scanf("%d", &n) == 1) {
            memset(d + 1, 0, n * 4);
            memset(h + 1, 0, n * 4);
            edc = 0; g = 0;
            for (int i = 1; i < n; ++i) {
                int x = read(), y = read();
                Add(x, y); Add(y, x);
            }
            if (n == 1) g = 1;
            for (int x = 1; x <= n && !g; ++x) {
                if (d[x] == 1) g = Solve(e[h[x]].t, 0, 0);
                else {
                    for (int i = h[x]; i && !g; i = e[i].n) {
                        for (int j = e[i].n; j && !g; j = e[j].n) {
                            g = Solve(e[j].t, x, 0) & Solve(e[i].t, x, 0);
                            if (g) {
                                for (int k = h[x]; k && g; k = e[k].n)
                                    g = Solve(e[k].t, x, 2);
                            }
                        }
                    }
                }
            }
            puts(g ? "Yes" : "No");
        }
        return 0;
    }
    

    解法四

    • 造完数据突然想起来解法三加个减枝会怎么样,就记一下Dfs了多少遍,超过1e7次就认为不可行,然后拿到了70分的好成绩,卡了一波,变成40分,倒这加边,还是40

    • 不过肯定还有别的减枝,当然减的越好得的分越多

    解法五

    • 要提出一条链当作主干,放在第一行,然后其他的点放在第二行,然后考虑什么样的点不能放在第二行

      • 度为1的点显然可以

      • 度为二的点且另一边连出去的链会分叉

      • 度为三的点且另两边至少一条连出去的链会分叉

      • 度超过三的点,一行放不下

    • 如果将一个点看作是在主干上的点,周围连着1个或2个不能放在第二行的点,那么可以将这1个或两个点放在主干上,在多就放不下了,所以周围有3个及以上不能放在第二行的点的话,这颗树就不能在游戏里实现

    • 判断连出去的链会不会分叉,可以从叶子节点开始,将度数小于等于2的点删去,这样删去的点那一边连出去的链就一定不会分叉了(枚举点的时候就不枚举删去的点了)

    • 最后有个问题就是,如果有一个点周围有两个放不下的,然后就把这三个都放在主干上,这样就能放下。可是如果有很多个点都需要放在主干上,那会不会冲突呢,毕竟放在主干上的只能是一条链

    • 对于这个问题,就是如果冲突,就是说这些点不再一条链上,连出来的图形中有分叉点,可是想一下分叉点一定至少有三条路,这三个点一定都不能放在第二行,所以不会出现冲突

    Code

    Show Code
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    const int N = 1e5 + 5;
    
    int read(int x = 0, int f = 1, char c = getchar()) {
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
        return x * f;
    }
    
    struct Edge {
        int n, t;
    }e[N*2];
    int h[N], edc, d[N];
    
    void Add(int x, int y) {
        e[++edc] = (Edge) {h[x], y}; h[x] = edc; d[x]++;
    }
    
    bool v[N], g;
    int n, c[N];
    
    void Dfs(int x, int fa) {
        v[x] = 1;
        for (int i = h[x], y; i; i = e[i].n)
            if (d[y=e[i].t] == 2 && y != fa) Dfs(y, x);
    }
    
    int main() {
        freopen("sgame.in", "r", stdin);
        freopen("sgame.out", "w", stdout);
        while (scanf("%d", &n) == 1) {
            memset(v + 1, 0, n);
            memset(d + 1, 0, n * 4);
            memset(c + 1, 0, n * 4);
            memset(h + 1, 0, n * 4);
            g = 1; edc = 0;
            for (int i = 1; i < n; ++i) {
                int x = read(), y = read();
                Add(x, y); Add(y, x);
            }
            for (int i = 1; i <= n; ++i)
                if (d[i] == 1) Dfs(i, 0);
            for (int x = 1; x <= n; ++x)
                for (int i = h[x]; i; i = e[i].n)
                    c[x] += v[e[i].t];
            for (int x = 1; x <= n && g; ++x) {
                if (v[x]) continue;
                int cnt = 0;
                for (int i = h[x]; i; i = e[i].n) {
                    int y = e[i].t;
                    if (d[y] == 2 && !c[y]) cnt++;
                    else if (d[y] == 3 && !c[y]) cnt++;
                    else if (d[y] == 3 && c[y] == 1) cnt++;
                    else if (d[y] >= 4) cnt++;
                }
                if (cnt > 2) g = 0;
            }
            puts(g ? "Yes" : "No");
        }
        return 0;
    }
    
  • 相关阅读:
    谷哥的小弟学后台(29)——动态代理
    HDU
    jni 入门 android的C编程之旅 --->环境搭建&&helloworld
    C# 开发系列(二)
    C# 开发系列(一)
    ajax跨域实现api 接口调用
    dependency injection(2)
    要读的书单
    dependency injection
    php dependency innjection
  • 原文地址:https://www.cnblogs.com/shawk/p/14517633.html
Copyright © 2020-2023  润新知