AtCoder Beginner Contest 352 A~E(F更新中...)

A. AtCoder Line(判断)

题意

有 N N N个车站,列车的运行有两种方向,即 1 → n 1 \rightarrow n 1→n和 n → 1 n \rightarrow 1 n→1两种。

问,从 x x x点到 y y y点,仅乘坐一次列车,是否会经过站点 z z z。

分析

判断 z z z点是否出现在 x x x点到达 y y y点的路线中即可。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

void solve() {
    int n, x, y, z;
    cin >> n >> x >> y >> z;
    if (x > y) {
        if (z >= y && z <= x) {
            cout << "Yes" << endl;
        } else {
            cout << "No" << endl;
        }
    } else {
        if (z <= y && z >= x) {
            cout << "Yes" << endl;
        } else {
            cout << "No" << endl;
        }
    }
}

int main() {
    solve();
    return 0;
}

B.Typing(字符串匹配)

题意

有两个字符串,一个想要打出的字符串S,一个是实际打出字符串T,请你输出当前字符串T中正确字符所在的下标。

分析

进行双指针进行字符串匹配,每次匹配上后输出下标即可。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

void solve() {
    string s, t;
    cin >> s >> t;
    int len_s = s.size(), len_t = t.size();
    for (int i = 0, j = 0; i < len_t; i++) {
        if (s[j] != t[i]) {

        } else {
            cout << i + 1 << ' ';
            j++;
        }
    }
}

int main() {
    solve();
    return 0;
}

C. Standing On The Shoulders(枚举)

题意

有 n n n个人,每个人有一个肩膀的高度以及头顶的高度。

你可以任意重排这 n n n个人,排序完成后,第一个人将站在地面上,后面的每一个人均站在前一个人的肩膀上,问,最优方案下,最高的人的头顶距离地面的最高高度是多少?

分析

观察发现,前 n − 1 n - 1 n−1个人对最后高度的贡献只有他的肩膀高度,而最后一个人对最后高度的贡献只有他的头顶高度,因此,可以先统计所有人的肩膀高度之和,然后依次枚举每个人作为最后一个人的高度即可(即肩膀高度之和减去当前人的肩膀高度再加上头部高度)。

代码

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

struct Node {
    ll x, y;
} a[200005];

void solve() {
    int n;
    cin >> n;
    ll sum = 0;
    for (int i = 0; i < n; i++) {
        cin >> a[i].x >> a[i].y;
        sum += a[i].x;
    }
    ll ans = 0;
    for (int i = 0; i < n; i++) {
        ans = max(ans, sum - a[i].x + a[i].y);
    }
    cout << ans << endl;
}

int main() {
    solve();
    return 0;
}

D. Permutation Subsequence(滑动窗口+set)

题意

给出一个包含 1 ∼ n 1 \sim n 1∼n的一个排列,当你从这个排列中取出其中 k k k个数字,如果这 k k k个数字满足以下条件,那么就是一个好的序列:

  • 取出的数字下标分别为 i 1 , i 2 , ... , i k i_1, i_2, \ldots, i_k i1,i2,...,ik,且 i i < i 2 < ... < i k i_i < i_2 < \ldots < i_k ii<i2<...<ik

  • 将取出的 k k k个数字进行排序后,第一个数字为 a a a,后面的数字依次为 a + 1 , a + 2 , a + 3 , ... , a + k − 1 a + 1, a + 2, a + 3, \ldots, a + k - 1 a+1,a+2,a+3,...,a+k−1。

请你求出所有好的序列中, i k − i 1 i_k - i_1 ik−i1的最小值。

分析

不难想到,所有好的序列必然是将原数组排序,任取其中连续的 k k k个数字,那么难点就在于快速得到每一段区间对应的数字原本下标的最大最小值(数组同时记录数字以及数字开始时的下标)。

如果掌握线段树等计算区间极值的算法,就可以直接枚举区间计算答案。

以下给出一个特殊做法,固定一个长度为 k k k的窗口,并使用两个set维护区间内的数字所在的原下标,两个set一个从小到大排序,一个从大到小排序。这样,每次移动完窗口后,只需要取出两个set的第一个元素,就能知道区间内数字原本下标的最大最小值,每次更新区间的时间复杂度为 O ( l o g n ) O(logn) O(logn)。

这样,记录所有窗口中的最大下标减最小下标的最小值即可。

Hint

可以通过 ∗ ( s e t . b e g i n ( ) ) *(set.begin()) ∗(set.begin())获取set中的第一个元素

代码

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

struct Node{
    ll a, id;
}a[200005];

ll n, k;

set<int, greater<int> > st1;
set<int, less<int> > st2;

void solve() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        cin >> a[i].a;
        a[i].id = i;
    }
    int ans = INT_MAX;
    sort(a + 1, a + n + 1, [&](Node o, Node o1) {
        if (o.a != o1.a) return o.a < o1.a;
        return o.id < o1.id;
    });
    for (int i = 1; i <= k; i++) {
        st1.insert(a[i].id);
        st2.insert(a[i].id);
    }
    ans = *(st1.begin()) - *(st2.begin());
    for (int i = k + 1; i <= n; i++) {
        st1.erase((a[i - k].id));
        st1.insert(a[i].id);
        st2.erase((a[i - k].id));
        st2.insert(a[i].id);
        ans = min(ans, *(st1.begin()) - *(st2.begin()));
    }
    cout << ans << endl;
}

int main() {
    solve();
    return 0;
}

E.Clique Connect(并查集)

题意

给出一个包含 n n n个点的图,你将会对这个图进行以下操作 M M M次:

  • 给出一个集合 S S S,以及一个费用 C C C,将所有属于集合中的点两两建边,所有边的边权均为 C C C.

完成操作后,问,这个图上的最小生成树的权值是多少?

分析

本题是并查集模板题。

由于每次对一个集合中建的边权都是相同的,那么不需要记录所有的边,只要要保证这个集合中的点连通即可,这里选择将每个点与集合中前一个点建边。

然后就是经典的Kruscal算法,将所有边按边权排序,然后按边权从小到达遍历边,并使用并查集进行维护,当两个点不在同一个集合中时,就在这两个点之间建边,并记录费用以及连的边数。

结束操作后,如果没有连上 n − 1 n - 1 n−1条边,就说明不存在最小生成树,输出-1。否则,输出记录的费用。

代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

struct Node{
    ll u, v, cost;
    friend bool operator < (const Node &o1, const Node &o2) {
        return o1.cost < o2.cost;
    }
}num[400005];

ll n, m, cnt, ans, sum, f[400005];

int find(int x) {
    return f[x] == x ? x : f[x] = find(f[x]);
}

void merge(Node node) {
    int fu = find(node.u);
    int fv = find(node.v);
    if (fu != fv) {
        f[fu] = fv;
        ans += node.cost;
        sum++;
    }
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int k, c;
        cin >> k >> c;
        int pre = -1;
        for (int j = 1; j <= k; j++) {
            int a;
            cin >> a;
            if (j > 1) {
                num[cnt++] = Node{pre, a, c};
            }
            pre = a;
        }
    }
    sort(num, num + cnt);
    for (int i = 1; i <= n; i++) f[i] = i;
    for (int i = 0; i < cnt; i++) {
        merge(num[i]);
    }
    if (sum != n - 1) {
        cout << -1 << endl;
    } else {
        cout << ans << endl;
    }
    return 0;
}

F.Estimate Order

更新中...

赛后交流

在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。

群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

相关推荐
七十二五1 小时前
matlab数据批量保存为excel,文件名,行和列的名称设置
经验分享·算法·matlab·青少年编程·矩阵·excel
阿巴~阿巴~1 小时前
C_深入理解指针(五) —— sizeof和strlen的对比、数组和指针笔试题解析、指针运算笔试题解析
c语言·开发语言·数据结构·算法
爱吃龙利鱼2 小时前
web群集--nginx常见的几种负载均衡调度算法的配置过程和效果展示
运维·算法·nginx·云原生·负载均衡
酷酷的崽7984 小时前
【数据结构】——原来排序算法搞懂这些就行,轻松拿捏
数据结构·算法·排序算法
八月的雨季 最後的冰吻5 小时前
C--字符串函数处理总结
c语言·前端·算法
阿拉伯的劳伦斯2927 小时前
LeetCode第一题(梦开始的地方)
数据结构·算法·leetcode
Mr_Xuhhh7 小时前
C语言深度剖析--不定期更新的第六弹
c语言·开发语言·数据结构·算法
吵闹的人群保持笑容多冷静7 小时前
2024CCPC网络预选赛 I. 找行李 【DP】
算法
桃酥4038 小时前
算法day22|组合总和 (含剪枝)、40.组合总和II、131.分割回文串
数据结构·c++·算法·leetcode·剪枝
山脚ice8 小时前
【Hot100】LeetCode—55. 跳跃游戏
算法·leetcode