AtCoder Beginner Contest 302

这篇具有很好参考价值的文章主要介绍了AtCoder Beginner Contest 302。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

A - Attack (abc302 a)

题目大意

给定怪物的血量\(a\)和你每次攻击扣除的血量 \(b\),问打多少次怪物才会死。

解题思路

答案即为\(\lceil \frac{a}{b} \rceil = \lfloor \frac{a + b - 1}{b} \rfloor\)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    LL a, b;
    cin >> a >> b;
    cout << (a + b - 1) / b << '\n';

    return 0;
}



B - Find snuke (abc302 b)

题目大意

给定一个二维网格,格子上有字母,找到一连串位置,使得其字符串为\(snuke\),要求这一连串位置俩俩相邻,即有共边或共点。这意味着可以横竖对角线。

解题思路

枚举起点,枚举方向(8个方向),依次判断即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int h, w;
    cin >> h >> w;
    vector<string> a(h);
    for(auto &i : a)
        cin >> i;
    string target = "snuke";
    vector<array<int, 2>> ans;
    auto check = [&](int x, int y, int dx, int dy){
        vector<array<int, 2>> tmp;
        for(int i = 0; i < target.size(); ++ i){
            if (x >= h || x < 0 || y >= w || y < 0)
                return false;
            if (a[x][y] != target[i])
                return false;
            tmp.push_back({x, y});
            x += dx;
            y += dy;
        }
        ans = tmp;
        return true;
    };
    auto solve = [&](){
        for(int i = 0; i < h; ++ i){
            for(int j = 0; j < w; ++ j){
                for(int x = -1; x <= 1; ++ x)
                    for(int y = -1; y <= 1; ++ y){
                        if (x == 0 && y == 0)
                            continue;
                        if (check(i, j, x, y)){
                            return;
                        }
                    }

            }
        }
    };
    solve();
    for(auto &i : ans)
        cout << i[0] + 1 << ' ' << i[1] + 1 << '\n';

    return 0;
}



C - Almost Equal (abc302 c)

题目大意

给定\(n\)个字符串,问能否排个序,使得俩俩字符串恰好仅一个位置上的字母不同。

解题思路

范围不大,直接\(O(n!)\)枚举排序,再 \(O(nm)\)判断即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n, m;
    cin >> n >> m;
    vector<string> s(n);
    for(auto &i : s)
        cin >> i;
    vector<int> id(n);
    iota(id.begin(), id.end(), 0);
    auto check = [&](){
        do{
            bool ok = true;
            for(int i = 0; i < n - 1; ++ i){
                int x = id[i], y = id[i + 1];
                int cnt = 0;
                for(int j = 0; j < m; ++ j)
                    cnt += (s[x][j] != s[y][j]);
                if (cnt != 1){
                    ok = false;
                    break;
                }
            }
            if (ok)
                return true;
        }while(next_permutation(id.begin(), id.end()));
        return false;
    };
    if (check())
        cout << "Yes" << '\n';
    else 
        cout << "No" << '\n';

    return 0;
}



D - Impartial Gift (abc302 d)

题目大意

给定两个数组\(a,b\),要求从中各选一个数,使得俩数的差值不超过 \(d\),问俩数和的最大值。

解题思路

先排个序,然后枚举\(a\)的每个数,在\(b\)中找到第一个不大于 \(a+d\)的值 ,然后取最大值即可。因为排了序,可以二分找,也可以因为枚举的\(a\)是递增的,一个指针从\(b\)中一路扫过去。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n, m;
    LL d;
    cin >> n >> m >> d;
    vector<LL> a(n), b(m);
    for(auto &i : a)
        cin >> i;
    for(auto &i : b)
        cin >> i;
    sort(a.begin(), a.end());
    sort(b.begin(), b.end());
    int pos = 0;
    LL ans = -1;
    for(int i = 0; i < n; ++ i){
        while(pos < m && b[pos] - a[i] <= d){
            ++ pos;
        }
        if (pos != 0 && abs(a[i] - b[pos - 1]) <= d){
            ans = max(ans, a[i] + b[pos - 1]);
        }
    }
    cout << ans << '\n';

    return 0;
}



E - Isolation (abc302 e)

题目大意

给定一张图,\(n\)个点,无边。有以下两种操作:

  • 1 u v,为\(u, v\)连一条边
  • 2 u,删除与\(u\)相连的每条边

对于每个操作,输出孤立点数量,即度数为 \(0\)的数量。

解题思路

按照上述题意模拟即可,每条边只会添加一次,删除一次,因此复杂度为\(O(q)\)

因为存的是双向边,删\(u\)的边时,比如删除的边是 \((u,v)\),要避免在删 \(v\)的边时将 \((u,v)\)再删一次,因此用了一个 \(set\)记录当前的边,其中规定了编号小的在前。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n, q;
    cin >> n >> q;
    vector<int> du(n, 0);
    vector<vector<int>> edge(n);
    int ans = n;
    auto add = [&](int x){
        if (du[x] == 0)
            -- ans;
        du[x] ++;
    };
    auto mine = [&](int x){
        if (du[x] == 1)
            ++ ans;
        du[x] --;
    };
    set<array<int, 2>> edges;
    while(q--){
        int op;
        cin >> op;
        if (op == 1){
            int u, v;
            cin >> u >> v;
            -- u, -- v;
            edge[u].push_back(v);
            edge[v].push_back(u);
            add(u);
            add(v);
            int minn = min(u, v), maxx = u + v - minn;
            edges.insert({minn, maxx});
        }else{
            int u;
            cin >> u;
            -- u;
            for(auto &v : edge[u]){
                int minn = min(u, v), maxx = u + v - minn;
                auto it = edges.find({minn, maxx});
                if (it != edges.end()){
                    edges.erase(it);
                    mine(u);
                    mine(v);
                }
                edge[u].clear();
            }
        }
        cout << ans << '\n';
    }

    return 0;
}



F - Merge Set (abc302 f)

题目大意

给定\(n\)个集合,每个集合包含了 \(1 \sim m\)的一些数。可以进行一种操作,选择两个交集不为空的集合,得到它们的并集。

问最少进行多少次操作,可以得到一个包含 \(1\)\(m\)的集合。

解题思路

集合与集合之间,根据交集不为空的关系,有连边。但由于\(n\)\(10^5\)的大小,因此不能 \(O(n^2)\)建边。

但由于所有集合的所有数加起来只有 \(5e5\),如果一个集合 \(i\)有数字 \(j\),我们可以 连一条\(i \to j\)的边,让数字 \(j\)充当集合与集合之间的中介。这样边数只有 \(5e5\)条。

即有两类点,一类是表示集合的点,一类是表示数字的点,集合\(\to\)数字的边权为 \(0\),数字\(\to\)集合的边权为 \(1\)

答案就是从\(1\)号点到 \(m\)号点的最短路距离减一。

因为边权只有 \(0\)\(1\),且在搜索时边权是交替出现的,所以直接 \(BFS\)即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;

const int inf = 1e9 + 7;

int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n, m;
    cin >> n >> m;
    vector<vector<array<int, 2>>> edge(n + m);
    for(int i = 0; i < n; ++ i){
        int x;
        cin >> x;
        while(x--){
            int v;
            cin >> v;
            -- v;
            edge[v].push_back({m + i, 1});
            edge[m + i].push_back({v, 0});
        }
    }
    vector<int> dis(n + m, inf);
    dis[0] = 0;
    queue<array<int, 2>> team;
    team.push({dis[0], 0});
    while(!team.empty()){
        auto [expect, u] = team.front();
        team.pop();
        for(auto &[v, w] : edge[u]){
            if (dis[u] + w < dis[v]){
                dis[v] = dis[u] + w;
                team.push({dis[v], v});
            }
        }
    }
    if (dis[m - 1] == inf)
        dis[m - 1] = 0;
    cout << dis[m - 1] - 1 << '\n';

    return 0;
}



G - Sort from 1 to 4 (abc302 g)

题目大意

给定一个仅包含\(1,2,3,4\)的数组,一次操作可以交换任意两个数。

问最少进行多少次交换,使得数组不严格升序。

解题思路

<++>文章来源地址https://www.toymoban.com/news/detail-452008.html

神奇的代码



Ex - Ball Collector (abc302 h)

题目大意

给定一棵树,每个点有两个值。

对于\(v = 2,3,...,n\) ,问从点\(1\)到点 \(v\)的最短路径途径的每个点中,各选一个数,其不同数的个数的最大值。

解题思路

<++>

神奇的代码



到了这里,关于AtCoder Beginner Contest 302的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • AtCoder Beginner Contest 310

    感觉F又双叒叕写复杂了 点杯咖啡,要 (p) 元,但可以用一个优惠券,使得咖啡只要 (q) 元,但你需要额外购买 (n) 个商品中(价格为 (a_i) )的一个。 问点杯咖啡的最小价格。 考虑直接买还是使用优惠券,使用优惠券的话就选 (n) 个商品中价格最小的。 两种情况取最小

    2024年02月16日
    浏览(28)
  • AtCoder Beginner Contest 320

    给定 (a,b) ,输出 (a^b + b^a) 。 因为数不超过 (10) ,可以直接用 pow 计算然后转成 (int) 。不会有精度损失。 神奇的代码 给定一个字符串 (s) ,求长度最长的回文串。 因为长度只有 (100) ,可以直接枚举子串,然后暴力判断是不是回文串(翻转后是否和自身相同),复杂

    2024年02月08日
    浏览(38)
  • AtCoder Beginner Contest 348

    给定 (n) ,输出 (ooxooxoox...) ,长度为 (n) 。 按题意模拟即可。 神奇的代码 给定 (n) 个点,对每个点,求出与其距离最远的点的下标。 (n) 只有 (100) ,对于每个点,花 (O(n)) 遍历每个点最大化距离,时间复杂度为 (O(n^2)) 。 神奇的代码 (n) 个豌豆,每个豌豆有美味值

    2024年04月08日
    浏览(42)
  • AtCoder Beginner Contest 304

    依次给定每个人的姓名和年龄,排成一圈。从年龄最小的人依次输出姓名。 找到年龄最小的,依次输出就好了。 神奇的代码 给定一个数字,如果其超过三位数,则仅保留其最高三位,低位数字全部置为0。 读一个 string ,直接赋值即可。 神奇的代码 给定 (n) 个人的坐标,第

    2024年02月07日
    浏览(39)
  • AtCoder Beginner Contest 329

    劳累一天不该写题,启发式合并都写错了 给定一个字符串,将每个字符输出出来,中间留个空格。 遍历输出即可。 神奇的代码 给定一个数组,找出次大的数。 遍历一下,从非最大的数求一个最大值即可。 神奇的代码 给定一个字符串,问有多少个连续的子串,其由一个字母

    2024年02月05日
    浏览(75)
  • AtCoder Beginner Contest 339

    给一个网址,问它的后缀是多少。 找到最后的\\\'.\\\'的位置,然后输出后面的字符串即可。 python 可以一行。 神奇的代码 二维网格,上下左右相连,左上原点。初始全部为白色,位于原点,面朝上。 进行 (n) 次操作,每次操作,将当前格子颜色黑白反转,然后 如果原来是白色

    2024年02月19日
    浏览(31)
  • AtCoder Beginner Contest 340

    给定等差数列的 首项 、 末项 、 公差 。 输出这个等差数列。 从 首相 依次累加 公差 到 末项 即可。 神奇的代码 依次进行 (Q) 次操作,分两种。 1 x ,将 x 放到数组 (a) 的末尾。 2 k ,输出数组 (a) 的倒数第 (k) 项。 用 vector 模拟即可,操作 2 可快速寻址访问。 神奇的代

    2024年02月19日
    浏览(33)
  • AtCoder Beginner Contest 314

    怎么好多陌生单词 审核怎么这么逆天,半小时还没审完 给定 (pi) 的值以及数 (n) ,要求保留 (n) 位小数输出,不四舍五入。 字符串形式储存然后截取末尾即可。 神奇的代码 (n) 个人玩轮盘赌游戏,简单说就是一个转盘有 (37) 个数字以及一个箭头,箭头会等概率停在某

    2024年02月13日
    浏览(40)
  • AtCoder Beginner Contest 308

    这几天在收拾东西搬家,先附上代码,晚点补上题解 补完了 感觉这次FG都写不太明白 给定八个数,问是否满足以下要求: 不严格升序 每个数在 (100 sim 675) 之间 每个数都是 (25) 的倍数 依次对每个数判断是否符合这三个条件即可。 神奇的代码 高桥吃 (n) 份寿司,寿司分

    2024年02月11日
    浏览(30)
  • AtCoder Beginner Contest 345

    给定一个字符串,问是不是形如 ======...==== 的字符串。 根据长度构造出期望的字符串,再判断是否相等即可。 神奇的代码 给定 (a) ,输出 (lceil frac{a}{10} rceil) 上下取整的转换, (lceil frac{a}{10} rceil = lfloor frac{a + 9}{10} rfloor) 。用下取整即可。 Python 的 // 是下取证,

    2024年03月21日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包