2023河南萌新联赛第(一)场:河南农业大学(部分题解)

文章提供了几道算法编程竞赛中的题目,包括动物朋友(双指针)、松鼠排序(并查集)、Reverse问题(思维)、迷宫探险(最短路)、合唱比赛(模拟)和以撒和隐藏房间(暴力枚举)。每道题都附有解题思路和通过所有测试用例的AC代码,帮助读者理解和解决这类问题。
摘要由CSDN通过智能技术生成

目录

E:动物朋友(双指针)

AC代码:

F:松鼠排序(并查集)

AC代码:

G:Reverse(思维)

AC代码:

H:迷宫探险(最短路)

AC代码:

J:合唱比赛(模拟)

AC代码:

K:以撒和隐藏房间(暴力枚举)

AC代码:


本次比赛的链接:

2023河南萌新联赛第(一)场:河南农业大学_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ

E:动物朋友(双指针)

思路:我们可以记录快指针和慢指针之间的快乐值,若此快乐值小于所需快乐值,则让快指针++,若此快乐值大于所需快乐值则让慢指针++,快乐值相等则方案数加一

AC代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;

void solve() {
    int i, j, k, n, m;
    cin >> n >> m;
    vector<int>nums(n, 0);
    for (i = 0; i < n; i++) {
        cin >> nums[i];
    }
    int left = 0, right = 0;
    int cnt = 0, ans = 0;
    for (right = 0; right < n; right++) {
        cnt += nums[right];
        while (left <= right && cnt > m) {
            cnt -= nums[left];
            left++;
        }
        if (cnt == m) ans++;
    }
    cout << ans << endl;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int t;
    t = 1;
    while (t--) {
        solve();
    }
    
    system("pause");
    return 0;
}

F:松鼠排序(并查集)

思路:对于每个nums[i]与i不相等的位置,在并查集中把a[i]i两个点合并,然后查看有几个集合,最终答案为每个集合块的大小减一的和,即ans = ∑(size - 1),例如假设其中一个块为3 1 2,我们要将其变为1 2 3,此时size = 3,只需交换两次即可完成排序

AC代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;

vector<int>fa;
void init(int n) {
    fa.resize(n + 1, 0);
    for (int i = 0; i < fa.size(); i++) {
        fa[i] = i;
    }
}
int find(int x) {
    if (fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}
void setunion(int a, int b) {
    int x = find(fa[a]);
    int y = find(fa[b]);
    if (x != y) fa[x] = y;
}

void solve() {
    int i, j, k, n;
    cin >> n;
    vector<int>nums(n, 0);
    init(n);
    for (i = 0; i < n; i++) {
        cin >> nums[i];
    }
    for (i = 0; i < n; i++) {
        if (nums[i] != i + 1) {
            setunion(nums[i], i + 1);
        }
    }
    map<int, int>mp;
    for (i = 1; i <= n; i++) {
        mp[find(fa[i])]++;
    }
    ll ans = 0;
    for (auto [x, y] : mp) {
        ans += y - 1;
    }
    cout << ans << endl;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int t;
    t = 1;
    while (t--) {
        solve();
    }
    
    system("pause");
    return 0;
}

G:Reverse(思维)

思路:通过观察我们可以发现,反转后的最长连续1的串为此01串中最大连续1的字串和次大连续1的字串和,所以我们将这两部分加起来即为最终答案

AC代码:
 

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;

void solve() {
    int i, j, k, n;
    cin >> n;
    string s;
    cin >> s;
    vector<int>nums;
    for (i = 0; i < s.length(); i++) {
        int cnt = 0;
        bool flag = false;
        while (s[i] == '1') {
            flag = true;
            i++;
            cnt++;
        }
        if (flag) i--;
        if (cnt != 0) nums.push_back(cnt);
    }
    ll ans = 0;
    sort(nums.begin(), nums.end(), greater<int>());
    for (i = 0; i < 2 && i < nums.size(); i++) {
        ans += nums[i];
    }
    cout << ans << endl;

}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int t;
    t = 1;
    while (t--) {
        solve();
    }
    
    system("pause");
    return 0;
}

H:迷宫探险(最短路)

思路:本题难点在于建图,对于此迷宫,我们可以从左至右,从上至下对其进行1 ~ n * m进行编号,根据题意,在弹射器上弹射不消耗时间,而正常移动消耗1单位时间,则我们可以建图,对于每个 ‘.’ ,若周围四个方向合法,它向相邻四个单位建边的边权为1,对于每个‘*’,若周围四个方向合法,则它向距离它相应距离的四个点单位建边的边权为0,对于‘#’则不建边,然后对所建图跑一边最短路即可,时间复杂度为O(k * log(n * m))

AC代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;

typedef struct {
    int v, w;
}edge;
vector<pii>dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
vector<vector<edge>>G(500005);
vector<bool>visit;
vector<ll>dist;
int n, m;
void dijkstra(int s) {
    int len = n * m;
    dist.resize(len + 1, INT_MAX);
    visit.resize(len + 1, false);
    dist[s] = 0;
    priority_queue<pii>Q;
    Q.push({0, s});
    while (!Q.empty()) {
        auto t = Q.top();
        Q.pop();
        int u = t.second;
        if (visit[u]) continue;
        visit[u] = true;
        for (auto ed : G[u]) {
            int v = ed.v, w = ed.w;
            if (dist[v] > dist[u] + w) {
                dist[v] = dist[u] + w;
                Q.push({-dist[v], v});
            }
        }
    }
}
void solve() {
    int i, j, k;
    cin >> n >> m;
    vector<vector<int>>laby(n + 1, vector<int>(m + 1, 0));
    for (i = 0; i < n; i++) {
        string s;
        cin >> s;
        for (j = 0; j < s.length(); j++) {
            if (s[j] == '#') laby[i + 1][j + 1] = -1;
            else laby[i + 1][j + 1] = 0;
        }
    }
    cin >> k;
    for (i = 0; i < k; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        laby[a][b] = c;
    }
    for (i = 1; i <= n; i++) {
        for (j = 1; j <= m; j++) {
            if (laby[i][j] > 0) {
                int new_x, new_y;
                new_x = i - laby[i][j];
                if (new_x >= 1 && laby[new_x][j] != -1) G[(i - 1) * m + j].push_back({(new_x - 1) * m + j, 0});
                new_x = i + laby[i][j];
                if (new_x <= n && laby[new_x][j] != -1) G[(i - 1) * m + j].push_back({(new_x - 1) * m + j, 0});
                new_y = j - laby[i][j];
                if (new_y >= 1 && laby[i][new_y] != -1) G[(i - 1) * m + j].push_back({(i - 1) * m + new_y, 0});
                new_y = j + laby[i][j];
                if (new_y <= m && laby[i][new_y] != -1) G[(i - 1) * m + j].push_back({(i - 1) * m + new_y, 0});
            } else if (laby[i][j] == 0) {
                int new_x, new_y;
                for (auto dir : dirs) {
                    new_x = i + dir.first;
                    new_y = j + dir.second;
                    if (new_x >= 1 && new_x <= n && new_y >= 1 && new_y <= m && laby[new_x][new_y] != -1) {
                        G[(i - 1) * m + j].push_back({(new_x - 1) * m + new_y, 1});
                    }
                }
            }
        }
    }
    dijkstra(1);
    if (dist[n * m] == INT_MAX) cout << -1 << endl;
    else cout << dist[n * m] << endl;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int t;
    t = 1;
    while (t--) {
        solve();
    }
    
    system("pause");
    return 0;
}

J:合唱比赛(模拟)

思路:依题意进行模拟即可

AC代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;

void solve() {
    int i, j, k, n;
    cin >> n;
    vector<int>nums1(n, 0);
    for (i = 0; i < n; i++) {
        cin >> nums1[i];
    }
    vector<int>nums2(nums1);
    nums1.push_back(1);
    sort(nums1.begin(), nums1.end());
    nums2.push_back(100);
    sort(nums2.begin(), nums2.end());
    double res1 = 0;
    double res2 = 0;
    for (i = 1; i < nums1.size() - 1; i++) {
        res1 += nums1[i];
        res2 += nums2[i];
    }
    res1 = res1 * 1.0 / (n - 1);
    res2 = res2 * 1.0 / (n - 1);
    printf("%.6lf %.6lf", res1, res2);

}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int t;
    t = 1;
    while (t--) {
        solve();
    }
    
    system("pause");
    return 0;
}

K:以撒和隐藏房间(暴力枚举)

思路:依题意对每个格子进行枚举判断即可

AC代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;

vector<string>G;
vector<pii>dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
int n, m;
bool judje(int x, int y) {
    int new_x, new_y;
    int ans = 0;
    for (auto dir : dirs) {
        new_x = x + dir.first;
        new_y = y + dir.second;
        if (new_x >= 0 && new_x < n && new_y >= 0 && new_y < m) {
            if (G[new_x][new_y] == '2') return false;
            if (G[new_x][new_y] == '1') ans++;
        }
    }
    if (ans == 3) return true;
    return false;
}
void solve() {
    int i, j, k;
    cin >> n >> m;
    G.resize(n);
    for (i = 0; i < n; i++) {
        cin >> G[i];
    }
    ll ans = 0;
    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            if (G[i][j] == '0' && judje(i, j)) ans++;
        }
    }
    if (ans > 0) {
        cout << "YES" << endl;
        cout << ans << endl;
    } else {
        cout << "NO" << endl;
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int t;
    t = 1;
    while (t--) {
        solve();
    }
    
    system("pause");
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值