武汉工程大学第三届ACM程序设计选拔赛(正式赛)题解

Posted 康次学长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了武汉工程大学第三届ACM程序设计选拔赛(正式赛)题解相关的知识,希望对你有一定的参考价值。

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

感谢牛客网为此次比赛提供在线评测环境

A. 疯狂动物城

此题改至ACWing 240 食物链
此题知识点:带权并查集

#include <iostream>

using namespace std;

const int N = 5e4 + 5, mod = 4;
int n, m, cnt;
int d[N], pre[N];

int find(int x)
{
    if (x != pre[x]) {
        int root = find(pre[x]);
        d[x] = (d[x] + d[pre[x]]) % mod;
        pre[x] = root;
    }
    return pre[x];
}

int main()
{
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++)
        pre[i] = i;
    while (m--) {
        int t, x, y;
        scanf("%d %d %d", &t, &x, &y);
        if (x < 1 || x > n || y < 1 || y > n || t != 1 && x == y) {
            cnt++;
            continue;
        }
        int k = t - 1;
        int px = find(x), py = find(y);
        if (px == py && ((d[x] - d[y]) % mod + mod) % mod != k) {
            cnt++;
            continue;
        }
        if (px != py) {
            pre[px] = py;
            d[px] = ((k - d[x] + d[y]) % mod + mod) % mod;
        }
    }
    printf("%d\\n", cnt);
    return 0;
}

方法二:扩展域并查集
作者不是很懂,只能把大佬的代码搬过来
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=47751034

B. 密室逃脱

此题比较简单的做法是直接Dijkstra,如果传送门的两端都不是陷阱,并且不是相邻的点,那就将两端的边权设置为3。如果不习惯从下标0开始计数,可以先将所有的点的横纵坐标都+1,最后如果有输出点再将横纵坐标都-1

#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
const int N = 310;
const int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
int n, m, q;
int stx, sty, edx, edy;
char mp[N][N];
vector<PII> edges[N][N];
int dis[N][N];
bool vis[N][N];

int Dijkstra()
{
    memset(dis, 0x3f, sizeof dis);
    priority_queue<PIII, vector<PIII>, greater<PIII>> heap;
    heap.push({0, {stx, sty}});
    dis[stx][sty] = 0;
    while (!heap.empty()) {
        int distance = heap.top().first;
        int a = heap.top().second.first, b = heap.top().second.second;
        heap.pop();
        if (vis[a][b])
            continue;
        vis[a][b] = true;
        if (a == edx && b == edy)
            return distance;
        for (int i = 0; i < 4; i++) {
            int x = a + dx[i], y = b + dy[i];
            if (!(x >= 1 && x <= n && y >= 1 && y <= m && mp[x][y] != '#' && dis[x][y] > distance + 1))
                continue;
            dis[x][y] = distance + 1;
            heap.push({dis[x][y], {x, y}});
        }
        for (auto t : edges[a][b]) {
            int x = t.first, y = t.second;
            if (!(mp[x][y] != '#' && dis[x][y] > distance + 3))
                continue;
            dis[x][y] = distance + 3;
            heap.push({dis[x][y], {x, y}});
        }
    }
    return -1;
}

int main()
{
    cin >> n >> m >> q;
    for (int i = 1; i <= n; i++) {
        cin >> mp[i] + 1;
        for (int j = 1; j <= m; j++)
            if (mp[i][j] == 'S')
                stx = i, sty = j;
            else if (mp[i][j] == 'T')
                edx = i, edy = j;
    }
    while (q--) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        a++, b++, c++, d++;
        edges[a][b].push_back({c, d});
        edges[c][d].push_back({a, b});
    }
    cout << Dijkstra() << endl;
    return 0;
}

C. 露营?料理!

此题的纸质版的地方由于工作人员疏忽, ∑ \\sum 的下标 i = 0 i=0 i=0写成了 i = 1 i=1 i=1,并且没有交代 w 0 w_0 w0恒等于0,对选手造成了干扰,在此感到非常抱歉。
此题知识点:前缀和+二分+双关键字排序。
前缀和求完之后需要把 w 0 w_0 w0的值放入到前缀和中,该元素的第二个关键字也要设置为0。
二分不是只有一种写法,在已经升序排列的数组 s s s中,求 s i ≤ x s_i \\le x six s i < x , s i > x s_i < x,s_i > x si<xsi>x s i ≥ x s_i \\ge x six 的下标 i i i,这四种二分写法是有区别的。进阶指南上面说只有10%的程序员会写二分

≥ x \\ge x x的下界

    int l = 1, r = n + 1;
    a[n + 1] = 0x3f3f3f3f;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (a[mid] >= x) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }

    if (l == n + 1) {
        puts("Not Found");
    } else {
        printf("%d\\n", a[l]);
    }

> x > x >x的下界

    int l = 1, r = n + 1;
    a[n + 1] = 0x3f3f3f3f;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (a[mid] > x) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }

    if (l == n + 1) {
        puts("Not Found");
    } else {
        printf("%d\\n", a[l]);
    }

≤ x \\le x x的上界

    int l = 0, r = n;
    a[0] = 0xc0c0c0c0;
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if (a[mid] <= x) {
            l = mid;
        } else {
            r = mid - 1;
        }
    }

    if (l == 0) {
        puts("Not Found");
    } else {
        printf("%d\\n", a[l]);
    }

< x < x <x的上界

    int l = 0, r = n;
    a[0] = 0xc0c0c0c0;
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if (a[mid] < x) {
            l = mid;
        } else {
            r = mid - 1;
        }
    }

    if (l == 0) {
        puts("Not Found");
    } else {
        printf("%d\\n", a[l]);
    }

此题标程

# include <iostream>
# include <cstdio>
# include <algorithm>

typedef long long ll;

const int N = 1e5 + 5;

int n;

struct Sum {
    int ans;
    int id;

    const bool operator < (const Sum& rhs) const {
        return ans < rhs.ans || (ans == rhs.ans && id < rhs.id);
    }
};

int w[N];
Sum sum[N];

int main() {
    int m;
    std::cin >> n >> m;

    for (int i = 1; i <= n; i++) {
        scanf("%d", &w[i]);
    }

    for (int i = 1; i <= n; i++) {
        sum[i].ans = sum[i-1].ans + w[i];
        sum[i].id = i;
    }

    sum[n + 1].ans = sum[n + 1].id = 0;
    std::sort(sum + 1, sum + 2 + n);

    sum[0].ans = sum[0].id = 0xc0c0c0c0;

    while (m--) {
        int k;
        scanf("%d", &k);      

        int l = 0; 
        int r = n + 1;

        while (l < r) {
            int mid = (l + r + 1) >> 1;
            if (sum[mid].ans <= k) {
                l = mid;
            } else {
                r = mid - 1;
            }
        }

        if (l &

以上是关于武汉工程大学第三届ACM程序设计选拔赛(正式赛)题解的主要内容,如果未能解决你的问题,请参考以下文章

2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛正式赛) 部分题题解

2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛正式赛) 部分题题解

个人赛组2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)-正式赛

2019 年「计算机科学与工程学院」新生赛 暨ACM集训队选拔赛 # 1

A777 吉林大学ACM集训队选拔赛(重现赛)

CCPC网络赛2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛(重赛) 签到题5题