zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 179

    比赛链接:https://atcoder.jp/contests/abc179/tasks

    A - Plural Form

    题意

    给出一个由小写字母组成的单词,如果单词以 $s$ 结尾,在单词的末尾加上 $es$,否则在单词的末尾加上 $s$ 。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        string s;
        cin >> s;
        cout << s + (s.back() == 's' ? "es" : "s") << "
    ";
        return 0;
    }

    B - Go to Jail

    题意

    给出一对骰子投掷 $n$ 次的结果,问是否有连续三次两个骰子的点数相同。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        cin >> n;
        vector<int> x(n), y(n);
        for (int i = 0; i < n; i++)
            cin >> x[i] >> y[i];
        for (int i = 0; i + 2 < n; i++) {
            if (x[i] == y[i] and x[i + 1] == y[i + 1] and x[i + 2] == y[i + 2]) {
                cout << "Yes" << "
    ";
                return 0;
            }
        }
        cout << "No" << "
    ";
        return 0;
    }

    C - A x B + C

    题意

    给出一个正整数 $n$,问有多少不同的三元组 $(a, b, c)$ 满足 $a,b,c > 0$ 且 $a imes b + c = n$ 。

    题解

    枚举 $a$ 的值,与之对应的 $b$ 的最大值为 $lfloor frac{n}{a} floor$,然后判断是否都能取到即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        cin >> n;
        long long ans = 0;
        for (int a = 1; a <= n; a++) {
            ans += n / a - (n % a == 0);
        }
        cout << ans << "
    ";
        return 0;
    }

    D - Leaping Tak

    题意

    给出 $k$ 个区间,区间并集中的整数为每次可以选择行走的距离,问在数轴上从点 $1$ 走到点 $n$ 的路径数目。

    题解

    与上一场的D题类似,可以考虑如下代码:

    dp[1] = 1;
    for (int i = 1; i < n; i++) {
        for (int j = 0; j < k; j++) {
            for (int k = l[j]; k <= r[j]; k++) {
                (dp[i + k] += dp[i]) %= MOD;
            }
        }
    }

    但是 $O_{(n^2k)}$ 的复杂度明显会超时。

    注意到第三层循环为区间操作,所以可以考虑用差分或线段树降低复杂度。

    代码一

    差分,时间复杂度为 $O_{(nk)}$ 。

    #include <bits/stdc++.h>
    using namespace std;
    constexpr int MOD = 998244353;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n, k;
        cin >> n >> k;
        vector<int> l(k), r(k);
        for (int i = 0; i < k; i++)
            cin >> l[i] >> r[i];
        vector<long long> dp(2 * n + 100);
        dp[1] = 1;
        dp[2] = -1;
        for (int i = 1; i <= n; i++) {
            dp[i] += dp[i - 1];
            dp[i] = (dp[i] % MOD + MOD) % MOD;
            for (int j = 0; j < k; j++) {
                dp[i + l[j]] += dp[i];
                dp[i + r[j] + 1] -= dp[i];
            }
        }
        cout << dp[n] << "
    ";
        return 0;
    }

    代码二

    线段树,时间复杂度为 $O_{(nlog_nk)}$ 。

    #include <bits/stdc++.h>
    #define lson i << 1
    #define rson i << 1 | 1
    #define mid ((l + r) >> 1)
    using namespace std;
    constexpr int N = 2e5 + 100;
    constexpr int MOD = 998244353;
    long long sum[N << 2], lazy[N << 2];
    void build(int i, int l, int r) {
        if (l == r) {
            sum[i] = 0;
            return;
        }
        build(lson, l, mid);
        build(rson, mid + 1, r);
        sum[i] = sum[lson] + sum[rson];
    }
    void push_down_lazy(int i, int l, int r) {
        if (lazy[i] != 0) {
            (sum[lson] += lazy[i] * (mid - l + 1)) %= MOD;
            (sum[rson] += lazy[i] * (r - mid)) %= MOD;
            (lazy[lson] += lazy[i]) %= MOD;
            (lazy[rson] += lazy[i]) %= MOD;
            lazy[i] = 0;
        }
    }
    void update(int i, int l, int r, int L, int R, int val) {
        if (L <= l and r <= R) {
            (sum[i] += 1LL * val * (r - l + 1) % MOD) %= MOD;
            (lazy[i] += val) %= MOD;
            return;
        }
        push_down_lazy(i, l, r);
        if (L <= mid) update(lson, l, mid, L, R, val);
        if (R > mid) update(rson, mid + 1, r, L, R, val);
        sum[i] = (sum[lson] + sum[rson]) % MOD;
    }
    long long query(int i, int l, int r, int L, int R) {
        if (L <= l and r <= R) {
            return sum[i];
        }
        push_down_lazy(i, l, r);
        long long res = 0;
        if (L <= mid) res += query(lson, l, mid, L, R);
        if (R > mid) res += query(rson, mid + 1, r, L, R);
        return res % MOD;
    }
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n, k;
        cin >> n >> k;
        vector<int> l(k), r(k);
        for (int i = 0; i < k; i++)
            cin >> l[i] >> r[i];
        build(1, 1, n);
        update(1, 1, n, 1, 1, 1);
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < k; j++) {
                if (i + l[j] <= n) {
                    update(1, 1, n, i + l[j], min(n, i + r[j]), query(1, 1, n, i, i));
                }
            }
        }
        cout << query(1, 1, n, n, n) << "
    ";
        return 0;
    }

    E - Sequence Sum

    题意

    $a_1 = x, a_{n+1} = a_n^2 % m$,计算 $displaystyle{sum_{i=1}^n a_i}$ 。

    题解

    找出循环节的起点和终点即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        long long n, x, m;
        cin >> n >> x >> m;
        const int N = min(n + 1, m + 2);
        vector<int> a(N);
        vector<int> vis(m);
        a[1] = x;
        vis[x] = 1;
        long long ans = 0;
        for (int i = 2; i < N; i++) {
            a[i] = a[i - 1] * a[i - 1] % m;
            if (vis[a[i]]) {
                long long sum1 = accumulate(a.begin(), a.begin() + vis[a[i]], 0LL);
                vector<int> cycle;
                for (int j = vis[a[i]]; j < i; j++) {
                    cycle.push_back(a[j]);
                }
                n -= vis[a[i]] - 1;
                long long sum2 = accumulate(cycle.begin(), cycle.end(), 0LL);
                long long sum3 = accumulate(cycle.begin(), cycle.begin() + n % cycle.size(), 0LL);
                cout << sum1 + sum2 * (n / cycle.size()) + sum3 << "
    ";
                return 0;
            } else {
                vis[a[i]] = i;
            }
        }
        ans = accumulate(a.begin(), a.end(), 0LL);
        cout << ans << "
    ";
        return 0;
    }

    F - Simplified Reversi

    题意

    有一个 $n imes n$ 的棋盘,棋盘中间 $(n-2) imes (n-2)$ 的方阵中为黑子,棋盘的最右列和最下行为白子。

    接下来有 $q$ 次操作:

    • $(1, x)$:在棋盘的第一行的 $x$ 列放置一枚白子,白字与该列最近的白子之间均变为白子
    • $(2, x)$:在棋盘的第一列的 $x$ 行放置一枚白子,白字与该行最近的白子之间均变为白子

    问 $q$ 操作之后还有多少个黑子。

    题解

    更新最左列和最上行的同时存储移动过程中黑子个数固定的列和行。(也可以直接用二维线段树但我不会

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n, q;
        cin >> n >> q;
        long long ans = 1LL * (n - 2) * (n - 2);
        vector<int> row(n + 1), col(n + 1);
        int pos_row = n, pos_col = n;
        for (int i = 0; i < q; i++) {
            int op, pos;
            cin >> op >> pos;
            if (op == 1) {
                if (pos < pos_col) {
                    ans -= pos_row - 2;
                    while (pos_col > pos) col[pos_col--] = pos_row - 2;
                } else {
                    ans -= col[pos];
                }
            } else {
                if (pos < pos_row) {
                    ans -= pos_col - 2;
                    while (pos_row > pos) row[pos_row--] = pos_col - 2;
                } else {
                    ans -= row[pos];
                }
            }
        }
        cout << ans << "
    ";
        return 0;
    }
  • 相关阅读:
    eclipse常用快捷键
    Sql server 问题诊断
    Oracle 表格大小分析
    VM虚拟机增加磁盘空间
    Linux搭建Nexus+Maven私人仓库
    Linux 下安装Git 版本管理工具 使用记录
    Jenkins 环境打建设 Linux
    Oracle 数据库用户表大小分析
    Windgb 其他常用命令
    Windbg 查内存占用
  • 原文地址:https://www.cnblogs.com/Kanoon/p/13702225.html
Copyright © 2011-2022 走看看