zoukankan      html  css  js  c++  java
  • 第二届计算机与信息安全学院程序设计竞赛题解

    经出题人同意,决定把此次比赛的题解放在此处供大家参考,如果有纰漏请及时反馈!

    1212 刺激战场

    题目:http://acm.guet.edu.cn/problem/view/1212.html

    思路:

    建立二分图:左半部分代表每行,右半部分代表每列。而行顶点i和列顶点j之间的连线就代表图 (i, j) 处有一个玩家。例如对于输入范例可建立以下二分图:

     

    要求最少操作次数即求该二分图的最小点覆盖集,也就是最大匹配。这里使用了dinic算法求最大匹配,即先将二分图转化为网络流,再进行计算。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int kMax = 20000 + 10;
    const int kInf = 1e9;
    
    struct node {
        int v, cost;
        node(int _v, int _cost) : v(_v), cost(_cost) {}
    };
    
    int s, t, n;
    int d[kMax];
    vector<node> table[kMax];
    bool bfs() {
        memset(d, -1, sizeof(d));
        queue<int> q;
        q.push(s);
        d[s] = 0;
        while (!q.empty()) {
            int u = q.front(); q.pop();
            for (int i = 0;i < table[u].size();++ i) {
                int v = table[u][i].v;
                if (table[u][i].cost > 0 && d[v] == -1) {
                    q.push(v);
                    d[v] = d[u] + 1;
                }
            }
        }
        return d[t] != -1;
    }
    int dfs(int u, int flow) {
        if(u == t) return flow;
        int res = 0;
        for (int i = 0;i < table[u].size();++ i) {
            int v = table[u][i].v;
            if (table[u][i].cost > 0 && d[v] == d[u] + 1) {
                int tmp = dfs(v, min(flow, table[u][i].cost));
                flow -= tmp;
                table[u][i].cost -= tmp;
                res += tmp;
                for (int j = 0;j < table[v].size();++ j) {
                    if (table[v][j].v == u) {
                        table[v][j].cost += tmp;
                        break;
                    }
                }
                if (flow == 0) break;
            }
        }
        if (res == 0) d[u] = -1;
        return res;
    }
    int dinic() {
        int res = 0;
        while (bfs()) { res += dfs(s, kInf); }
        return res;
    }
    
    int main() {
        int m, a, b;
        scanf("%d%d", &n, &m);
        for (int i = 0;i < m;++ i) {
            scanf("%d%d", &a, &b);
            table[a].push_back({b + n, 1});
            table[b + n].push_back({a, 0});
        }
        s = 0;
        t = n + n + 1;
        for (int i = 1;i <= n;++ i) {
            table[s].push_back({i, 1});
            table[i].push_back({s, 0});
            table[i + n].push_back({t, 1});
            table[t].push_back({i + n, 0});
        }
        printf("%d
    ", dinic());
        return 0;
    }
    View Code

    1213 监督学习

    题目:http://acm.guet.edu.cn/problem/view/1213.html

    思路:

    标准答案应该是建立区间更新 + 区间查询的线段树,但是由于oj的限制导致数据量过小,以至于暴力也能过。对于暴力过的同学,出题人表示算你们运气好(#`O′)。

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    const int kMax = 1e5 + 10;
    
    struct node {
        int l, r;
        ll sum, add;
    } tree[kMax << 2];
    
    void pushup(int p) {
        tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
    }
    
    void pushdown(int p) {
        if (tree[p].add) {
            tree[p << 1].sum += (tree[p << 1].r - tree[p << 1].l + 1) * tree[p].add;
            tree[p << 1 | 1].sum += (tree[p << 1 | 1].r - tree[p << 1 | 1].l + 1) * tree[p].add;
            tree[p << 1].add += tree[p].add;
            tree[p << 1 | 1].add += tree[p].add;
            tree[p].add = 0;
        }
    }
    void build(int p, int l, int r) {
        tree[p].l = l;
        tree[p].r = r;
        tree[p].add = 0;
        if (l == r) {
            scanf("%lld", &tree[p].sum);
            return;
        }
        int m = (l + r) >> 1;
        build(p << 1, l, m);
        build(p << 1 | 1, m + 1, r);
        pushup(p);
    }
    
    ll query(int p, int l, int r) {
        if(l <= tree[p].l && r >= tree[p].r) return tree[p].sum;
        pushdown(p);
        int m = (tree[p].l + tree[p].r) >> 1;
        ll res = 0;
        if(l <= m) res += query(p << 1, l, r);
        if(r >= m + 1) res += query(p << 1 | 1, l, r);
        return res;
    }
    
    void update(int p, int l, int r, ll v) {
        if(l <= tree[p].l && r >= tree[p].r) {
            tree[p].sum += (tree[p].r - tree[p].l + 1) * v;
            tree[p].add += v;
            return;
        }
        pushdown(p);
        int m = (tree[p].l + tree[p].r) >> 1;
        if(l <= m) update(p << 1, l, r, v);
        if(r >= m + 1) update(p << 1 | 1, l, r, v);
        pushup(p);
    }
    
    
    int main() {
        int n, m, op, l, r;
        ll x;
        scanf("%d%d", &n, &m);
        build(1, 1, n);
        while (m --) {
            scanf("%d", &op);
            if(op == 1) {
                scanf("%d%d", &l, &r);
                printf("%lld
    ", query(1, l, r));
            } else {
                scanf("%d%d%lld", &l, &r, &x);
                update(1, l, r, x);
            }
        }
        return 0;
    }
    View Code

    1214 年会抽大奖

    题目:http://acm.guet.edu.cn/problem/view/1214.html

    思路:

    题意很简单,求组合数。解题需要用到数论中乘法逆元的知识,预处理出 n! 和 1/n! 的值。时间复杂度O(n + m)。

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    const int kMax = 1e6 + 5;
    const ll kMod = 1e9 + 7;
    
    ll fac[kMax] = {1, 1}, inv[kMax] = {1, 1}, f[kMax] = {1, 1};
    
    ll C(ll a, ll b) {
        if (a < b) return 0;
        return fac[a] * inv[b] % kMod * inv[a - b] % kMod;
    }
    
    void init() {
        for (int i = 2;i < kMax;++ i) {
            fac[i] = fac[i - 1] * i % kMod;
            f[i] = (kMod - kMod / i) * f[kMod % i] % kMod;
            inv[i] = inv[i - 1] * f[i] % kMod;
        }
    }
    
    
    int main() {
        int t;
        ll n, m;
        init();
        scanf("%d", &t);
        while (t --) {
            scanf("%lld%lld", &n, &m);
            printf("%lld
    ", C(n, m));
        }
        return 0;
    }
    View Code

    1215 教官的任务

    题目:http://acm.guet.edu.cn/problem/view/1215.html

    思路:

    签到题,直接合并后排序。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int kMax = 205;
    
    int main() {
        int n, m, nums[kMax];
        scanf("%d%d", &n, &m);
        for (int i = 0;i < n + m;++ i) { scanf("%d", &nums[i]); }
        sort(nums, nums + n + m);
        for (int i = 0;i < n + m;++ i) {
            if (i) printf(" ");
            printf("%d", nums[i]);
        }
        printf("
    ");
        return 0;
    }
    View Code

    1216 区块链

    题目:http://acm.guet.edu.cn/problem/view/1216.html

    思路:

    简单搜索题,dfs 一遍即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int kMax = 105;
    
    const int dx[] = {-1, 0, 1, 0, -1, -1, 1, 1};
    const int dy[] = {0, -1, 0, 1, -1, 1, -1, 1};
    
    int n, m;
    char table[kMax][kMax];
    bool vis[kMax][kMax];
    
    int dfs(int x, int y) {
        int res = 1;
        for (int i = 0;i < 8;++ i) {
            int tx = x + dx[i], ty = y + dy[i];
            if (tx >= 0 && tx < n && ty >= 0 && ty < m && table[tx][ty] == '*' && !vis[tx][ty]) {
                vis[tx][ty] = true;
                res += dfs(tx, ty);
            }
        }
        return res;
    }
    
    int main() {
        int res = 0;
        scanf("%d%d", &n, &m);
        for (int i = 0;i < n;++ i) { scanf("%s", table[i]); }
        for (int i = 0;i < n;++ i) {
            for (int j = 0;j < m;++ j) {
                if (table[i][j] == '*' && !vis[i][j]) {
                    vis[i][j] = true;
                    res = max(res, dfs(i, j));
                }
            }
        }
        printf("%d
    ", res);
        return 0;
    }
    View Code
  • 相关阅读:
    第01组 Beta冲刺(1/5)
    2019 SDN上机第6次作业
    2019 SDN上机第5次作业
    SDN课程阅读作业(2)
    USDT钱包对接交易所 寻找最便捷的USDT充提币API接口文档
    EOS区块链钱包开发教程
    XRP钱包对接教程
    usdt钱包如何跟交易所对接?
    BTC_ETH_USDT_自动充提币API接口,钱包对接交易所教程!
    BTC bitcoin-cli转账及交易的API使用教程
  • 原文地址:https://www.cnblogs.com/darklights/p/8674742.html
Copyright © 2011-2022 走看看