AtCoder Beginner Contest 322

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

A - First ABC 2 (abc322 A)

题目大意

给定一个字符串,找到最先出现ABC的位置。

解题思路

直接查找判断即可。

神奇的代码
#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;
    string s;
    cin >> n >> s;
    int pos = s.find("ABC");
    if (pos == string::npos)
        pos = -2;
    cout << pos + 1 << '\n';

    return 0;
}



B - Prefix and Suffix (abc322 B)

题目大意

给定字符串 st,问s是不是t的前缀和后缀。

解题思路

根据前后缀定义判断即可。这里试了下python

神奇的代码
n, m = map(int, input().split(' '))
s = input()
t = input()
prefix = t.startswith(s)
suffix = t.endswith(s)
if prefix and suffix:
    print(0)
elif prefix and not suffix:
    print(1)
elif not prefix and suffix:
    print(2)
else:
    print(3)



C - Festival (abc322 C)

题目大意

\(n\)天,有\(m\)天会放烟花。

问每一天,距离未来最近的放烟花的天数。

解题思路

两个双指针一样,一个指针指向当前天数,一个指针指向未来最近的放烟花的天数,两者差就是答案。然后两个指针不断往未来移动。

神奇的代码
#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<int> day(m);
    for (auto& i : day)
        cin >> i;
    int cur = 0;
    for (int i = 1; i <= n; ++i) {
        if (i > day[cur])
            ++cur;
        cout << day[cur] - i << '\n';
    }

    return 0;
}



D - Polyomino (abc322 D)

题目大意

给定三个多米诺骨牌,问能否不重叠地摆成\(4 \times 4\)的方格。

解题思路

数不大,直接暴力搜索。

考虑搜索方式,虽然给了个\(4 \times 4\)的多米诺骨牌的表示形式,但我们就枚举这个 \(4 \times 4\) 的方格的位置。

设想我们的画布就是一个\(4 \times 4\)的方格,然后枚举一个多米诺骨牌盖章左上角的位置(可以在这个画布之外),以及旋转的角度,然后一盖,在该区域的多米诺骨就被保留下来。最后我们就看该区域是否填满了,且没重叠,且无多米诺骨牌在外面。

代码实现里没有真正的盖,只取了盖在画布上的格子,方法类似于

神奇的代码
#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);
    array<array<string, 4>, 3> tu;
    int cnt = 0;
    for (auto& i : tu)
        for (auto& j : i) {
            cin >> j;
            cnt += count(j.begin(), j.end(), '#');
        }
    array<array<char, 4>, 4> page{};
    int dx1[2] = {1, -1};
    int dy1[2] = {1, -1};
    int dx2[2] = {1, -1};
    int dy2[2] = {-1, 1};
    auto fit1 = [&](int k, int x, int y, int d) {
        for (int i = 0; i < 4; ++i)
            for (int j = 0; j < 4; ++j) {
                int nx = x + dx1[d] * i, ny = y + dy1[d] * j;
                if (tu[k][i][j] == '#') {
                    if (nx >= 0 && nx < 4 && ny >= 0 && ny < 4) {
                        if (page[nx][ny] == '#') {
                            return false;
                        }
                        page[nx][ny] = '#';
                    } else {
                        return false;
                    }
                }
            }
        return true;
    };
    auto fit2 = [&](int k, int x, int y, int d) {
        for (int i = 0; i < 4; ++i)
            for (int j = 0; j < 4; ++j) {
                int nx = x + dx2[d] * j, ny = y + dy2[d] * i;
                if (tu[k][i][j] == '#') {
                    if (nx >= 0 && nx < 4 && ny >= 0 && ny < 4) {
                        if (page[nx][ny] == '#') {
                            return false;
                        }
                        page[nx][ny] = '#';
                    } else {
                        return false;
                    }
                }
            }
        return true;
    };
    function<bool(int)> ok = [&](int k) {
        if (k == 3) {
            return true;
        }
        auto bak = page;
        for (int x = -3; x <= 7; ++x)
            for (int y = -3; y <= 7; ++y) {
                for (int d = 0; d < 2; ++d) {
                    if (fit1(k, x, y, d)) {
                        if (ok(k + 1))
                            return true;
                    }
                    page = bak;
                    if (fit2(k, x, y, d)) {
                        if (ok(k + 1))
                            return true;
                    }
                    page = bak;
                }
            }
        return false;
    };
    if (cnt == 16 && ok(0))
        cout << "Yes" << '\n';
    else
        cout << "No" << '\n';

    return 0;
}


上述代码实际上没有真正旋转,在盖章的时候考虑了角度,而旋转\(90,270\)\(0,180\)的考虑逻辑不一样,因此代码会比较长,下述代码则真正旋转了矩阵,代码简洁点,不过运行时间会长一点点(指长了\(4ms\)

神奇的代码
#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);
    array<array<string, 4>, 3> tu;
    int cnt = 0;
    for (auto& i : tu)
        for (auto& j : i) {
            cin >> j;
            cnt += count(j.begin(), j.end(), '#');
        }
    array<array<char, 4>, 4> page{};
    auto fit = [&](int k, int x, int y) {
        for (int i = 0; i < 4; ++i)
            for (int j = 0; j < 4; ++j) {
                int nx = x + i, ny = y + j;
                if (tu[k][i][j] == '#') {
                    if (nx >= 0 && nx < 4 && ny >= 0 && ny < 4) {
                        if (page[nx][ny] == '#') {
                            return false;
                        }
                        page[nx][ny] = '#';
                    } else {
                        return false;
                    }
                }
            }
        return true;
    };
    auto rotate = [&](const array<string, 4>& a) {
        auto ret = a;
        for (int i = 0; i < a.size(); ++i) {
            for (int j = 0; j < a.front().size(); ++j)
                ret[j][a.size() - i - 1] = a[i][j];
        }
        return ret;
    };
    function<bool(int)> ok = [&](int k) {
        if (k == 3) {
            return true;
        }
        auto bak = page;
        for (int x = -3; x <= 7; ++x)
            for (int y = -3; y <= 7; ++y) {
                for (int r = 0; r < 4; ++r) {
                    if (fit(k, x, y)) {
                        if (ok(k + 1))
                            return true;
                    }
                    tu[k] = rotate(tu[k]);
                    page = bak;
                }
            }
        return false;
    };
    if (cnt == 16 && ok(0))
        cout << "Yes" << '\n';
    else
        cout << "No" << '\n';

    return 0;
}


E - Product Development (abc322 E)

题目大意

一个产品,有\(k\)个性能参数,初始为\(0\),要求进行一些提升计划,使得每个性能参数不小于 \(p\),且代价最小。

每个提升计划包含一个代价,以及对这\(k\)个性能参数提升的数值。

解题思路

注意到\(k,p\)最大都只有 \(5\)。考虑搜索状态,我们可以设 \(dp[i][a1][a2][a3][a4][a5]\)表示前 \(i\)个提升计划,使得最终性能参数分别为 \(a1,a2,a3,a4,a5\)的最小代价。转移就考虑当前提升计划选或不选即可。

但这里的 \(p\)不一定是 \(5\),也就是说这个 \(dp\)的维度不是固定的,但由于每一维度的取值只有 \(0 \sim p\)\(6\)种情况,最多 \(k=5\)维,因此我们可以把这最后的 \(k\)维压缩成一维的 \(6\)进制数表示。

由于 \(dp[i]\)只依赖于 \(dp[i-1]\),因此第一维可以滚动数组优化掉。

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

const LL inf = 1e18;

int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, k, p;
    cin >> n >> k >> p;
    int base = p + 1;
    const int sz = int(pow(base, k));
    vector<LL> dp(sz, inf);
    dp[0] = 0;
    auto dtr = [&](int x) {
        vector<int> ret(k);
        for (int i = k - 1; i >= 0; --i) {
            ret[i] = x % base;
            x /= base;
        }
        return ret;
    };
    auto tr = [&](const vector<int>& x) {
        int ret = 0;
        for (int i = 0; i < k; ++i) {
            ret = ret * base + x[i];
        }
        return ret;
    };
    for (int i = 0; i < n; ++i) {
        int c;
        cin >> c;
        vector<int> x(k);
        vector<LL> dp2 = dp;
        for (auto& i : x)
            cin >> i;
        for (int j = 0; j < sz; ++j) {
            auto now = dtr(j);
            for (int i = 0; i < k; ++i)
                now[i] = min(p, now[i] + x[i]);
            auto nxt = tr(now);
            dp2[nxt] = min(dp2[nxt], dp[j] + c);
        }
        dp.swap(dp2);
    }
    LL ans = dp.back();
    if (ans == inf)
        ans = -1;
    cout << ans << '\n';

    return 0;
}



F - Vacation Query (abc322 F)

题目大意

给定一个\(01\)\(s\)。维护两种操作。

  • \(1, l,r\),将\(s[l..r]\)的数字翻转。
  • \(2,l,r\),问\(s[l..r]\)中最长的连续的\(1\)的长度。

解题思路

不考虑修改,仅考虑查询。

考虑如何求解,对于每个\(r\),我们要找最小的 \(l\)满足 \(sum[r] - sum[l] = r - l\),其中 \(sum[i]\)表示 \(s[1..i]\)\(1\)的个数。

但这涉及到特定区间的信息,感觉难以维护。

注意到问的是连续的,还有一种思路是考虑区间信息的合并,即一个区间的最长连续段,要么在左区间,要么在右区间,要么是左区间的后缀和右区间的前缀合并起来。与此相关的其他信息(区间最长连续 \(1\)的前缀 、后缀长度、是否全是\(1\),这些信息都可以合并),因此可以用线段树维护区间的上述信息,对于每个区间答案,合并\(\log\)次区间信息即可得到 。

考虑修改,事实上就是把\(1\)看成 \(0\)\(0\)看成 \(1\)。因此我们分别对 \(0,1\)这两个数维护上述信息,修改时交换一下这两个信息即可。

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

const int N = 5e5 + 8;

class segment {
#define lson root << 1
#define rson root << 1 | 1

    struct node {
        struct info {
            int ans, l, r;
            bool all;
        } _info[2];
        bool flip;

        node operator+(const node& o) {
            node ret;
            ret.flip = 0;
            for (int i = 0; i < 2; ++i) {
                const auto &L = _info[i], R = o._info[i];
                ret._info[i].ans = max({L.ans, R.ans, L.r + R.l});
                ret._info[i].l = L.l;
                ret._info[i].r = R.r;
                if (L.all)
                    ret._info[i].l = L.l + R.l;
                if (R.all)
                    ret._info[i].r = L.r + R.r;
                ret._info[i].all = (L.all && R.all);
            }
            return ret;
        }

        void swap_info() { swap(_info[0], _info[1]); }

        int ans() { return _info[1].ans; }
    } a[N << 2];

  public:
    void build(int root, int l, int r, const string& s) {
        if (l == r) {
            a[root].flip = 0;
            for (int i = 0; i < 2; ++i) {
                auto& info = a[root]._info[i];
                info.l = info.r = info.all = info.ans = (s[l - 1] == '0' + i);
            }
            return;
        }
        int mid = (l + r) >> 1;
        build(lson, l, mid, s);
        build(rson, mid + 1, r, s);
        a[root] = a[lson] + a[rson];
    }

    void pushdown(int root) {
        if (a[root].flip) {
            a[lson].flip ^= 1;
            a[lson].swap_info();
            a[rson].flip ^= 1;
            a[rson].swap_info();
            a[root].flip = 0;
        }
    }

    void update(int root, int l, int r, int ll, int rr) {
        if (ll <= l && r <= rr) {
            a[root].flip ^= 1;
            a[root].swap_info();
            return;
        }
        pushdown(root);
        int mid = (l + r) >> 1;
        if (ll <= mid)
            update(lson, l, mid, ll, rr);
        if (rr > mid)
            update(rson, mid + 1, r, ll, rr);
        a[root] = a[lson] + a[rson];
    }

    node query(int root, int l, int r, int ll, int rr) {
        if (ll <= l && r <= rr) {
            return a[root];
        }
        pushdown(root);
        int mid = (l + r) >> 1;
        node L, R;
        if (ll <= mid)
            L = query(lson, l, mid, ll, rr);
        if (rr > mid)
            R = query(rson, mid + 1, r, ll, rr);
        if (ll > mid)
            return R;
        else if (rr <= mid)
            return L;
        else
            return L + R;
    }
} seg;

int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, q;
    cin >> n >> q;
    string s;
    cin >> s;
    seg.build(1, 1, n, s);
    while (q--) {
        int c, l, r;
        cin >> c >> l >> r;
        if (c == 1) {
            seg.update(1, 1, n, l, r);
        } else {
            auto ans = seg.query(1, 1, n, l, r);
            cout << ans.ans() << '\n';
        }
    }

    return 0;
}



G - Two Kinds of Base (abc322 G)

题目大意

给定\(n,x\),问有多少组 \((s,a,b)\),满足下述条件:

  • \(a,b \leq n\)
  • \(s\)是一个序列,长度随意, \(s_i < \min(10, a, b), s_1 \neq 0\)
  • \(s\)\(a\)进制的表示形式时,其值为\(sa\)\(b\)进制的表示形式时,其值为 \(sb\),要求 \(sa - sb = x\)

解题思路

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

神奇的代码



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

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

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

相关文章

  • AtCoder Beginner Contest 311

    给定一个字符串,问最短的一个前缀,包含 A B C 这三个字符。 注意到这个前缀的末尾字母一定是这三个字母中的一个,因此答案就是这三个字母出现位置最早的最大值。 神奇的代码 给定 (n) 个人的 (d) 天的空闲与否的情况,问最长的连续天,这 (n) 个人都空闲。 我们找

    2024年02月16日
    浏览(33)
  • AtCoder Beginner Contest 318

    咕咕咕,总力战还没打,凹不过卷狗,躺了.jpg 给定 (n, m, p) ,问有多少个 (i) 满足 (0 m+pi leq n) 减去初始的 (m) ,剩下的就是看 (p) 的倍数个数。 神奇的代码 一个二维空间,有 (n) 个矩形覆盖。 问有多大的空间被覆盖了。重复覆盖算一次。 空间大小只有 (100) ,矩形

    2024年02月10日
    浏览(30)
  • AtCoder Beginner Contest 328

    给定 (n) 个数字和一个数 (x) 。 问不大于 (x) 的数的和。 按找要求累计符合条件的数的和即可。 神奇的代码 给定一年的月数和一个月的天数。 问有多少对 ((i,j)) ,表示第 (i) 个月的第 (j) 日, (i,j) 的数位上每个数字都是一样的。 范围只有 (O(100^2)) ,枚举所有的

    2024年02月05日
    浏览(27)
  • AtCoder Beginner Contest 323

    有的人边上课边打abc 给定一个 (01) 字符串,问偶数位(从 (1) 开始) 是否全为 (0) 。 遍历判断即可。 神奇的代码 给定 (n) 个人与其他所有人的胜负情况。问最后谁赢。 一个人获胜次数最多则赢,若次数相同,则编号小的赢。 统计每个人的获胜次数,排个序即可。 神奇

    2024年02月08日
    浏览(22)
  • AtCoder Beginner Contest 299

    给定一个包含 |*. 的字符串,其中 | 两个, * 一个,问 * 是否在两个 | 之间。 找到两个 | 的下标 (l, r) 以及 * 的下标 (mid) ,看看是否满足 (l mid r) 即可。 神奇的代码 给定 (n) 个人的卡片,颜色为 (c_i) ,数字为 (r_i) 。 如果其中有颜色为 (T) 的牌,则该颜色中数字最大

    2023年04月23日
    浏览(15)
  • AtCoder Beginner Contest 324

    在高铁上加训! 给定 (n) 个数,问是否都相等。 判断是不是全部数属于第一个数即可。或者直接拿 set 去重。 神奇的代码 给定一个数 (N) ,问是否能表示成 (2^x3^y) 。 指数范围不会超过 (64) ,花 (O(64^2)) 枚举判断即可。 神奇的代码 给定一个字符串 (t) 和若干个字符串

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

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

    2024年04月08日
    浏览(33)
  • AtCoder Beginner Contest 325

    感觉错失了上分机会 给定姓和名,输出尊称,即姓+ san 。 按照题意模拟即可。 神奇的代码 给定 (n) 个地区的公司人数和对应的时区,规定上班时间为 (9:00-18:00) ,现召开一小时会议,上班期间的公司可以参加。问订个时间,能参与的人数的最大值。 枚举开会的时间,然后

    2024年02月08日
    浏览(23)
  • AtCoder Beginner Contest 330

    给定 (n) 个学生的分数,以及及格分 (x) ,问多少人及格了。 依次判断即可。 神奇的代码 回答 (n) 个问题,每个问题给定 (a,l,r) ,问函数 (f(x) = |x - a|) 在 ([l,r]) 的最小值。 全定义域下,最小值显然在 (x=a) 取得。绝对值函数图像是 (V) 型。 现在限定在 ([l,r]) ,则

    2024年02月05日
    浏览(108)
  • AtCoder Beginner Contest 332

    坐地铁时口糊了6题,回来写时结果爆 long long , 0 没有逆元,卡了好久 线上购物,买了 (n) 种物品,分别给出它们的单价和数量。 若总价少于 (s) 元,则需要支付 (k) 元邮费,否则包邮。 问总价多少。 求个和判断下是否加邮费即可。 神奇的代码 一个容量为 (G) 的玻璃杯

    2024年02月04日
    浏览(31)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包