第二届计算机与信息安全学院程序设计竞赛题解

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

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
原文地址:https://www.cnblogs.com/darklights/p/8674742.html