zoukankan      html  css  js  c++  java
  • 牛客小白月赛29全题解

    牛客小白月赛29全题解

    A.进攻

    题目链接:https://ac.nowcoder.com/acm/contest/8564/A

    思路:

    1. 将基地按防御值为第一关键字,价值为第二关键字从小到大排序。将战机按破坏力从小到大排序。
    2. 由于战机能破坏任意防御值比其破坏力小的基地,所以选择破坏防御值比其破坏力小的价值最大的基地即可
    3. 有2可以导出,先预处理出每个基地的价值的前缀最大值,这个最大值就是可以破坏该基地的战机所能获得的最大价值
    4. 从大到小扫遍历机和基地,将可以摧毁的且价值大于0的价值累加即为答案

    注意:1、价值可能为负数;2、在遍历的时候,在战机遍历完之前,基地可能已经遍历完了

    由于第二条,卡了近一个小时,wa了无数发。。。

    AC代码:

    #include <iostream>
    #include <algorithm>
    
    #define x first
    #define y second
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    const int N = 1e6+10;
    
    int n, m, a[N];
    PII dv[N];
    
    int main()
    {
        cin >> n >> m;
        for(int i = 0; i < n; i++) scanf("%d", &a[i]);
        for(int i = 0; i < m; i++) scanf("%d", &dv[i].x);
        for(int i = 0; i < m; i++) scanf("%d", &dv[i].y);
        sort(a, a + n);
        sort(dv, dv + m);
        int mv = -1e3 - 10;
        for(int i = 0; i < m; i++)
        {
            mv = max(mv, dv[i].y);
            dv[i].y = mv;
        }
        
        int ans = 0;
        for(int i = n - 1, j = m - 1; ~i && ~j;)
        {
            if(a[i] > dv[j].x)
            {
                if(dv[j].y > 0) ans += dv[j].y;
                else break;
                i--;
            }
            else j--;
        }
        cout << ans << endl;
        
        return 0;
    }
    

    B.二进制

    题目链接:https://ac.nowcoder.com/acm/contest/8564/B

    可以确定,一定可以通过三步与、或、异或得到最后的结果。

    观察01与、或、异或的值:

    与;            或:            异或:
    0 & 1 = 0      0 | 1 = 1       0 ^ 1 = 1
    1 & 1 = 1      1 | 1 = 1       1 ^ 1 = 0
    0 & 0 = 0      0 | 0 = 0       0 ^ 0 = 0
    1 & 0 = 0      1 | 0 = 1       1 ^ 0 = 1
    

    可以发现

    1. 0/1 & 1值不变0/1 | 0值不变0/1 ^ 0值不变
    2. 开始为0,结果为0;开始为1, 结果为0的情况是&0
    3. 开始为0,结果为1;开始为1, 结果为1的情况是|1
    4. 开始为0,结果为1;开始为1, 结果为0的情况是^0

    所以我们可以以0和220-1为初始值,然后经过所有操作后得结果,一位一位比较前后值的变化,依次推断出该位是&0还是|1还是^1

    AC代码:

    #include <iostream>
    #include <bitset>
    
    using namespace std;
    
    int n;
    bitset<20> ans1((1 << 20) - 1), ans2(0), ans3(0);
    
    int main()
    {
        cin >> n;
        int x1 = 0, x2 = (1 << 20) - 1;
        while(n--)
        {
            int op, a;
            scanf("%d%d", &op, &a);
            if(op == 1) x1 = x1 & a, x2 = x2 & a;
            else if(op == 2) x1 = x1 | a, x2 = x2 | a;
            else x1 = x1 ^ a, x2 = x2 ^ a;
        }
        cout << 3 << endl;
        for(int i = 0, j = 0; i < 20; i++, j++)
        {
            if(((x1 >> i) & 1) == 0 && ((x2 >> i) & 1) == 0) 
                ans1[j] = 0;
            else if(((x1 >> i) & 1) == 1 && ((x2 >> i) & 1) == 1) ans2[j] = 1;
            else if(((x1 >> i) & 1) == 1 && ((x2 >> i) & 1) == 0) ans3[j] = 1;
        }
    
        cout << 1 << ' ' << ans1.to_ulong() << endl;
        cout << 2 << ' ' << ans2.to_ulong() << endl;
        cout << 3 << ' ' << ans3.to_ulong() << endl;
    
        return 0;
    }
    

    C.积木

    题目链接:https://ac.nowcoder.com/acm/contest/8564/C

    构造题

    参考题解:积木_欢迎您的光顾awa-CSDN博客

    AC代码:

    /*
    采用构造方法:
    00 11
    00 11
    交替出现
    */
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int n;
        cin >> n;
        if(n & 1)
        {
            puts("-1");
            return 0;
        }
        
        for(int h = 1; h <= n; h++)
        {
            for(int k = ((h & 1) ? 0 : 1), i = 0; i < n; i += 2, k = (k + 1) % 2)
            {
                for(int x = k, j = 0; j < n; j += 2)
                {
                    printf("%d %d ", x, x);
                    x = (x + 1) % 2;
                }
                putchar('
    ');
                for(int x = k, j = 0; j < n; j += 2)
                {
                    printf("%d %d ", x, x);
                    x = (x + 1) % 2;
                }
                putchar('
    ');
            }
        }
        
        return 0;
    }
    

    D.种树

    题目链接:https://ac.nowcoder.com/acm/contest/8564/D

    根据题目要求可得,需要剪枝的次数(m = (n - 1) / 2),所以用大剪刀的次数为(ma = (m + 1) / 2)

    分析可得:如果我们在最开始就用大剪刀的话,后面用小剪刀会把最大值替换掉,也就是说先用大剪刀会被后面的小剪刀抵消掉。

    由此可的:从深度为ma的那一层点开始,到根节点全部用大剪刀,深度大于ma的全部用小剪刀。根据题意遍历完所有节点,同时更新。最后根节点的生命力即为结果。

    AC代码:

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 5e5+10;
    
    int n, m, ma, l, r, v, root;
    bool st[N];
    struct Node
    {
        int l, r, v;
        bool yz;
    }tr[N];
    
    void dfs(int root, int h)
    {
        int ls = tr[root].l, rs = tr[root].r;
        if(ls) dfs(ls, h + 1);
        if(rs) dfs(rs, h + 1);
        if(tr[ls].yz && tr[rs].yz)
        {
            if(h >= ma) tr[root].v = min(tr[ls].v, tr[rs].v);
            else tr[root].v = max(tr[ls].v, tr[rs].v);
        }
        tr[root].l = tr[root].r = 0, tr[root].yz = true;
    }
    
    int main()
    {
        cin >> n;
        m = n / 2;
        ma = (m + 1) / 2;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d", &l, &r);
            tr[i].l = l, tr[i].r = r, tr[i].yz = !(l && r);
            st[l] = st[r] = true;
        }
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &v);
            tr[i].v = v;
        }
        //找根节点
        for(int i = 1; i <= n; i++)
            if(!st[i])
            {
                root = i;
                break;
            }
        dfs(root, 0);
        cout << tr[root].v << endl;
        
        return 0;
    }
    

    E.考试

    题目链接:https://ac.nowcoder.com/acm/contest/8564/E

    首先遍历,计算出两人答案相同的题目数量t

    • (t(相同数量)<= n- k(答案正确的数量))时,相同的全对,不同的自己正确,ans = t + k
    • (t(相同数量)> n- k(答案正确的数量)),相同部分全对,剩余的相同部分全错,ans = n - (t - (n - k))

    AC代码:

    #include <iostream>
    
    using namespace std;
    
    const int N = 1010;
    
    int n, k;
    int a[N], t;
    
    int main()
    {
        cin >> n >> k;
        for(int i = 0; i < n; i++) scanf("%d", &a[i]);
        for(int i = 0; i < n; i++)
        {
            int x;
            scanf("%d", &x);
            if(x == a[i]) t++;
        }
        
        if(t <= n - k) cout << t + k << endl;
        else cout << n - (t - (n - k)) << endl;
        return 0;
    }
    

    F.项链

    题目链接:https://ac.nowcoder.com/acm/contest/8564/F

    写一个循环双链表即可,翻转就是l[]和r[]交换

    AC代码:

    #include <iostream>
    
    using namespace std;
    
    const int N = 2e5+10;
    
    int n, m, op, x, y;
    int e[N], l[N], r[N], idx, p[N], t[N];
    
    void insert_r(int a, int x)
    {
        e[idx] = x, p[x] = idx;
        l[idx] = a, r[idx] = r[a];
        l[r[a]] = idx, r[a] = idx++;
    }
    
    void insert_l(int a, int x)
    {
        e[idx] = x, p[x] = idx;
        r[idx] = a, l[idx] = l[a];
        r[l[a]] = idx, l[a] = idx++;
    }
    
    void remove(int a)
    {
        l[r[a]] = l[a];
        r[l[a]] = r[a];
    }
    
    void init(int n)
    {
        r[0] = 1, l[0] = 1;
        r[1] = 0, l[1] = 0;
        idx = 2;
        for(int i = 1; i <= n; i++) insert_r(idx - 1, i);
    }
    
    int main()
    {
        cin >> n >> m;
        init(n);
        while(m--)
        {
            scanf("%d", &op);
            if(op == 1 || op == 2) scanf("%d%d", &x, &y);
            
            if(op == 1)
            {
                remove(p[x]);
                insert_r(p[y], x);
            }
            else if(op == 2)
            {
                remove(p[x]);
                insert_l(p[y], x);
            }
            else if(op == 3)
            {
                for(int i = 0; i < idx; i++)
                {
                    int t = l[i];
                    l[i] = r[i], r[i] = t;
                }
            }
            else
            {
                for(int i = p[1], j = 1; j <= n; i = r[i], j++)
                {
                    if(i == 1 || !i)
                    {
                        j--;
                        continue;
                    }
                    if(j < n) printf("%d ", e[i]);
                    else printf("%d
    ", e[i]);
                }
            }
        }
        
        return 0;
    }
    

    G.涂色

    题目链接:https://ac.nowcoder.com/acm/contest/8564/G

    由于只能填0、1并且不能出现10,则可推出:按顺序填,一旦填了一个1,则后面只能是1。

    所以,1可以出现的位置数量n(每个位置可出现,且各不相同同)+1(全0的情况)即为答案。

    AC代码:

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int n;
        cin >> n;
        cout << n + 1 << endl;
        return 0;
    }
    

    H.圆

    题目链接:https://ac.nowcoder.com/acm/contest/8564/H

    直接判断即可:

    圆心的距离(d = sqrt{(x1 - x2)^2 + (y1 - y2)^2})

    • (d > r1 + r2quad(d^2 > (r1 + r2)^2))或者(d < |r1 - r2|quad(d^2 < (r1 - r2)^2))时,无交点
    • 否则有交点

    AC代码:

    #include <iostream>
    
    using namespace std;
    
    typedef long long LL;
    
    int t;
    LL x1, y1, r1, x2, y2, r2;
    
    int main()
    {
        cin >> t;
        while(t--)
        {
            cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2;
            LL d = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
            if(d > (r1 + r2) * (r1 + r2) || d <  (r1 - r2) * (r1 - r2)) puts("NO");
            else puts("YES");
        }
        
        return 0;
    }
    

    I.修改

    题目链接:https://ac.nowcoder.com/acm/contest/8564/I

    参考题解:牛客小白月赛29 - cumtljz - 博客园 (cnblogs.com)

    要使数组所有数都变为0,则其差分数组都变为0。对于一个操作[l,r,w],可使差分数组第l位变为0,因此,如果所有位置都能与第n+1位联通,那么就存在一些操作让差分数组都变成0。那么如果将每个操作[l,r,w]视为一条边,求最小生成树即为最小解(注意:对原数组区间操作,影响的是差分数组的l和r+1位)。

    AC代码:

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    typedef long long LL;
    
    const int N = 2e5+10, INF = 0x3f3f3f3f;
    
    int n, m, l, r, w;
    int p[N];
    struct Edge
    {
        int l, r, w;
        
        bool operator < (const Edge &W) const
        {
            return w < W.w;
        }
    }edges[N];
    
    
    int find(int x)
    {
        if(p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
    
    LL kruskal()
    {
        sort(edges, edges + m);
        for(int i = 1; i <= n + 1; i++) p[i] = i;
        
        LL res = 0, cnt = 0;
        for(int i = 0; i < m; i++)
        {
            int a = edges[i].l, b = edges[i].r, w = edges[i].w;
            a = find(a), b = find(b + 1);
            if(a != b)
            {
                res += w;
                cnt++;
                p[a] = b;
            }
        }
        
        if(cnt < n - 1) return INF;
        else return res;
    }
    
    int main()
    {
        cin >> n >> m;
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d%d", &l, &r, &w);
            edges[i] = {l, r, w};
        }
        
        LL t = kruskal();
        if(t == INF) puts("-1");
        else cout << t << endl;
        return 0;
    }
    

    J.克隆

    题目链接:https://ac.nowcoder.com/acm/contest/8564/J

    参考题解:牛客小白月赛29 - cumtljz - 博客园 (cnblogs.com)

    关于DFS序和欧拉序dfs序和欧拉序 - Styx-ferryman - 博客园 (cnblogs.com)

    AC代码:

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    const int N = 1e5+10;
    
    int n, m, k, ma;
    int h[N], e[4 * N], ne[4 * N], idx;
    int p[4 * N], cnt;
    bool st[N];
    
    void add(int a, int b)
    {
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    
    void dfs(int u)
    {
        st[u] = true;
        p[cnt++] = u;
        for(int i = h[u]; ~i; i = ne[i])
        {
            int j = e[i];
            if(st[j]) continue;
            dfs(j);
            p[cnt++] = u;
        }
    }
    
    int main()
    {
        cin >> n >> m >> k;
        ma = (2 * n + k - 1) / k;
        memset(h, -1, sizeof h);
        for(int i = 0; i < m; i++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            add(u, v), add(v, u);
        }
        dfs(1);
        
        puts("YES");
        int num = cnt / ma, k = 0;
        for(int i = 0; i < num; i++)
        {
            printf("%d", ma);
            for(int j = 0; j < ma; j++)
                printf(" %d", p[k++]);
            putchar('
    ');
        }
        
        if(cnt % ma)
        {
            printf("%d", cnt % ma);
            for(; k < cnt; k++) printf(" %d", p[k]);
            putchar('
    ');
        }
        
        return 0;
    }
    
  • 相关阅读:
    6. Flask请求和响应
    5. Flask模板
    FW:Software Testing
    What is the difference between modified duration, effective duration and duration?
    How to push master to QA branch in GIT
    FTPS Firewall
    Query performance optimization of Vertica
    (Forward)5 Public Speaking Tips That'll Prepare You for Any Interview
    (转)The remote certificate is invalid according to the validation procedure
    Change
  • 原文地址:https://www.cnblogs.com/grain-rain/p/14818106.html
Copyright © 2011-2022 走看看