AtCoder Beginner Contest 442

链接:https://atcoder.jp/contests/abc442

A – Count .

算法:

模拟。

思路:

无。

关键代码:

void miyan()
{
    string s;
    cin >> s;

    ll ans = 0;
    for (auto c : s)
        if (c == 'i' || c == 'j')
            ++ans;

    cout << ans << endl;
}

B – Music Player

算法:

模拟。

思路:

无。

关键代码:

void miyan()
{
    int Q;
    cin >> Q;

    int cnt = 0;
    bool ok = 0;
    while (Q--)
    {
        int op;
        cin >> op;
        if (op == 1)
            ++cnt;
        else if (op == 2)
            cnt = max(0, cnt - 1);
        else
            ok = !ok;

        if (ok && cnt >= 3)
            cout << "Yes" << endl;
        else
            cout << "No" << endl;
    }
}

C – Peer Review

算法:

图论,组合数。

思路:

定义 \(u\) 点的 \(cur = n – cnt(u) – 1\),每个点 \(u\) 的答案为 \(C_{cur}^{3}\)。

关键代码:

void miyan()
{
    int n, m;
    cin >> n >> m;
    vector<vector<int>> g(n + 1);
    for (int i = 1; i <= m; ++i)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    for (int i = 1; i <= n; ++i)
    {
        ll cur = n - g[i].size() - 1;

        if (cur < 3)
            cout << 0 << ' ';
        else
            cout << (cur * (cur - 1) * (cur - 2) / 6) << ' ';
    }

    cout << endl;
}

D – Swap and Range Sum

算法:

树状数组。

思路:

无。

关键代码:

struct BIT
{
    int n;
    vector<ll> tr;
    BIT(int _N)
    {
        n = _N;
        tr.resize(n + 1, 0);
    }

    void add(int x, ll v)
    {
        for (; x <= n; x += x & -x)
            tr[x] += v;
    }

    ll query(int l, int r)
    {
        auto ask = [&](int x)
        {
            ll ans = 0;
            for (; x; x -= x & -x)
                ans += tr[x];
            return ans;
        };

        return ask(r) - ask(l - 1);
    }
};

void miyan()
{
    int n, q;
    cin >> n >> q;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; ++i)
        cin >> a[i];

    BIT bit(n);
    for (int i = 1; i <= n; ++i)
        bit.add(i, a[i]);

    while (q--)
    {
        int op;
        cin >> op;

        if (op == 1)
        {
            int x;
            cin >> x;

            int val1 = a[x];
            int val2 = a[x + 1];
            swap(a[x], a[x + 1]);
            bit.add(x, -val1);
            bit.add(x + 1, -val2);
            bit.add(x, val2);
            bit.add(x + 1, val1);
        }
        else
        {
            int l, r;
            cin >> l >> r;

            cout << bit.query(l, r) << endl;
        }
    }
}

E – Laser Takahashi

极角排序,还没补。

F – Diagonal Separation 2

算法:

\(dp\),前缀和优化。

思路:

通过手玩样例不难发现,最后满足题目要求的网格,其每行白色格子的数量一定是非严格单调递减的且白色格子都在前 \(k\) 个位置,即第 \(i\) 行白色格子数量一定小于等于第 \(i – 1\) 行的白色格子数量。

考虑动态规划。

定义 \(dp[i][j]\) 为第 \(i\) 行只有前 \(j\) 个格子为白色的最少操作次数。

初始化第 \(1\) 行:

  • \(dp[1][i]_{i = 0}^{n} = i – cnt(1, 1, i) + cnt(1, i + 1, n)\)
  • 其中 \(cnt(row, l, r)\) 为第 \(row\) 行第 \(l\) 列到 \(r\) 列的白色格子数量。

状态转移:

  • \(dp[i][j]_{j = 0}^n = dp[i – 1][k]_{k = j}^{n} + i – cnt(i, 1, j) + cnt(i, j + 1, n)\)

其中 \(cnt\) 函数可以定义并预处理 \(pre[i][j]\) 和 \(suf[i][j]\) 前缀后缀数组,使其可以在 \(O(1)\) 时间内获得白色格子数量。

初始化与状态转移:

for (int i = 0; i <= n; ++i)
    dp[1][i] = i - pre[1][i] + suf[1][i + 1];

for (int i = 2; i <= n; ++i)
    for (int j = 0; j <= n; ++j)
        for (int k = j; k <= n; ++k)
            dp[i][j] = min(dp[i][j], dp[i - 1][k] + j - pre[i][j] + suf[i][j + 1]);

此时状态转移时间复杂度为 \(O(n ^ 3)\),而 \(n = 5000\),会超时,考虑优化掉一层循环。

不难想到优化 \(dp[i – 1][k]_{k = j}^{n}\),其只是获取前一层状态的后缀最小值,可以开一个数组存储后缀最小值,或者在转移第 \(i\) 层时逆序转移并定义 \(minn\) 为前一层的后缀最小值,跟随着转移共同更新。

此时状态转移代码为:

for (int i = 2; i <= n; ++i)
{
    int minn = INT_MAX;
    for (int j = n; j >= 0; --j)
    {
        minn = min(minn, dp[i - 1][j]);
        dp[i][j] = minn + j - pre[i][j] + suf[i][j + 1];
    }
}

由于只会用到上一层的状态,可以开滚动数组优化内存。

关键代码:

void miyan()
{
    int n;
    cin >> n;
    vector a(n + 1, vector<int>(n + 1, 0));
    for (int i = 1; i <= n; ++i)
    {
        string s;
        cin >> s;

        s = ' ' + s;
        for (int j = 1; j <= n; ++j)
            if (s[j] == '.')
                a[i][j] = 1;
    }

    vector pre(n + 1, vector<int>(n + 2, 0));
    vector suf(n + 1, vector<int>(n + 2, 0));
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= n; ++j)
            pre[i][j] = pre[i][j - 1] + a[i][j];

        for (int j = n; j >= 1; --j)
            suf[i][j] = suf[i][j + 1] + a[i][j];
    }

    vector dp(2, vector<int>(n + 1, INT_MAX));
    for (int i = 0; i <= n; ++i)
        dp[1 & 1][i] = i - pre[1][i] + suf[1][i + 1];

    for (int i = 2; i <= n; ++i)
    {
        int minn = INT_MAX;
        for (int j = n; j >= 0; --j)
        {
            minn = min(minn, dp[(i - 1) & 1][j]);
            dp[i & 1][j] = minn + j - pre[i][j] + suf[i][j + 1];
        }
    }

    int ans = INT_MAX;
    for (int i = 0; i <= n; ++i)
        ans = min(ans, dp[n & 1][i]);

    cout << ans << endl;
}

G – Lightweight Knapsack

    还没补。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇