gyouzasushi’s diary

競プロとか

AtCoder Beginner Contest 182 に参加しました

調子よかった回のことばっかり書いてる気がしてきたから、そうでもない回のことも書いておきます。
atcoder.jp

成績

f:id:gyouzasushi:20201109000757p:plainf:id:gyouzasushi:20201109000748p:plain

A - twiblr

問題:(リンク
B \leq 2\times A+100 の制約見落としてた。max とる必要なし

コードを表示

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
    ll a, b;
    cin >> a >> b;
    cout << max(0ll, (2 * a + 100) - b) << '\n';
}

B - Almost GCD

問題:(リンク
std::max_element 使うと楽?

コードを表示

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;
int main() {
    int n;
    cin >> n;
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    vector<int> cnt(1010, 0);
    for (int k = 2; k < 1010; k++) {
        rep(i, n) if (a[i] % k == 0) cnt[k]++;
    }
    cout << max_element(cnt.begin(), cnt.end()) - cnt.begin() << '\n';
}

C - To 3

問題:(リンク
場合分けした。でもbit全探索の方が楽だしバグらせないし賢いね。

コードを表示

#include <bits/stdc++.h>
#define sz(x) int(x.size())
using namespace std;
using ll = long long;
int main() {
    ll n;
    cin >> n;
    string s = to_string(n);
    vector<int> cnt(3);
    for (char c : s) cnt[(c - '0') % 3]++;
    if (n % 3 == 0) {
        cout << 0 << '\n';
    } else if (n % 3 == 1) {
        if (cnt[1] >= 1 && sz(s) > 1) {
            cout << 1 << '\n';
        } else if (cnt[2] >= 2 && sz(s) > 2) {
            cout << 2 << '\n';
        } else {
            cout << -1 << '\n';
        }
    } else if (n % 3 == 2) {
        if (cnt[2] >= 1 && sz(s) > 1) {
            cout << 1 << '\n';
        } else if (cnt[1] >= 2 && sz(s) > 2) {
            cout << 2 << '\n';
        } else {
            cout << -1 << '\n';
        }
    }
}

D - Wandering

問題:(リンク
累積累積maxみたいなのを見ればOK。

コードを表示

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;
using ll = long long;
template <class T>
bool chmax(T& a, const T& b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
int main() {
    int n;
    cin >> n;
    vector<ll> a(n);
    rep(i, n) cin >> a[i];
    vector<ll> maxs(n);
    maxs[0] = a[0];
    rep(i, n - 1) {
        a[i + 1] += a[i];
        maxs[i + 1] = max(maxs[i], a[i + 1]);
    }

    ll ans = 0, pos = 0;
    rep(i, n) {
        chmax(ans, pos + maxs[i]);
        pos += a[i];
    }
    cout << ans << '\n';
}

E - Akari

問題:(リンク
お前も鬼にならないか?ならない。
またまたグリッドを照らすんか、逆に Lamp とか Lamps とは何が違うんや?と少しフリーズしてしまってもったいない。ブロックとブロックの間に電球が存在するか?を縦横に全部みればOK。
配列外参照で1ペナ。めっちゃ配列外参照しちゃう。配列内参照が難しいんかもしれん。逆にね。

コードを表示

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;
int main() {
    int h, w, n, m;
    cin >> h >> w >> n >> m;
    vector<vector<bool>> lamp(h, vector<bool>(w));
    vector<vector<bool>> block(h, vector<bool>(w));
    rep(i, n) {
        int a, b;
        cin >> a >> b;
        lamp[--a][--b] = true;
    }
    rep(i, m) {
        int c, d;
        cin >> c >> d;
        block[--c][--d] = true;
    }

    vector<vector<bool>> ok(h, vector<bool>(w));
    rep(i, h) {
        rep(j, w) {
            if (lamp[i][j]) {
                int k = j;
                for (; k >= 0 && !block[i][k]; k--) {
                    ok[i][k] = 1;
                }
                k = j;
                for (; k < w && !block[i][k]; k++) {
                    ok[i][k] = 1;
                }
                j = k;
            }
        }
    }
    rep(j, w) {
        rep(i, h) {
            if (lamp[i][j]) {
                int k = i;
                for (; k >= 0 && !block[k][j]; k--) {
                    ok[k][j] = 1;
                }
                k = i;
                for (; k < h && !block[k][j]; k++) {
                    ok[k][j] = 1;
                }
                i = k;
            }
        }
    }
    int ans = 0;
    rep(i, h) rep(j, w) ans += ok[i][j];
    cout << ans << '\n';
}

F - Valid payments

問題:(リンク
タイトルと設定みた段階ですでに苦手意識が止まらん。お金払う系、解けたためしがない( Payment, Pay to Win )。

「ルンルンが店員に渡したコインのいずれかと同じ種類のコインが店員から返されることはありませんでした。」という条件から、N 種類のコインそれぞれについて(基本的には)店員が使うかルンルンが使うかの二択になる(どっちも使わない、もありだけど)。二択を繰り返す問題は DP、と歴史の教科書に書いてあるので、DP!!!
コンテスト終了には間に合わなかったけどなんとか解けて嬉しい。

コードを表示

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;
using ll = long long;
int main() {
    int n;
    ll x;
    cin >> n >> x;
    vector<ll> a(n);
    rep(i, n) cin >> a[i];

    auto f = [&](ll num, int i) {
        for (int j = n - 1; j > i; j--) num %= a[j];
        return num / a[i];
    };

    using P = pair<ll, int>;
    map<P, ll> memo;
    auto dp = [&](auto dp, ll num, int i) -> ll {
        if (i >= n) return 0;
        if (i == n - 1) return 1;
        if (memo.count(P(num, i))) return memo[P(num, i)];

        ll ret = 0;
        ll nnum = num / a[i + 1] * a[i + 1];

        ret += dp(dp, nnum, i + 1);
        if (f(num, i) > 0) ret += dp(dp, nnum + a[i + 1], i + 1);

        return memo[P(num, i)] = ret;
    };
    cout << dp(dp, x, 0) << '\n';
}

おわり

Highest まであと14
黄色まであと178