競技プログラミング
CHR_Virtual_08 解説
公開日:
2022/03/30
CHR_Virtual_08 解説

CHR_Virtual_08 の感想です。 気力があれば upsolve のついでに不定期投稿するかもね。

1. A. Last Letter

_ = input()
s = input()
print(s[-1])

2. B. Go Straight and Turn Right

n = int(input())
dy, dx = [0, 1, 0, -1], [1, 0, -1, 0]
pt = [0, 0]  # y, x
t = input()
k = 0
for c in t:
    if c == "S":
        pt[0] += dy[k]
        pt[1] += dx[k]
    else:
        k -= 1
        if k == -1:
            k = 3

# x, y
print(pt[1], pt[0])

3. C. Yamanote Line Game

interactive だった。Python なら print() 時に flush されるが C++ を使ったので endl する必要あり。

int main() {
    int n;
    cin >> n;
    int pos = 1;
    vector<bool> used(n * 2 + 2, false);
    for (int i = 0; i <= n; i++) {
        cout << pos << endl;
        if (i == n) break;
        used[pos] = true;
        int x;
        cin >> x;
        used[x] = true;
        while (used[pos]) {
            pos++;
        }
    }
    int _;
    cin >> _;
    return 0;
}

(3. に関して) ターミナル練習

以下、.py ファイルの名前は main.py であるとします。あなたのファイル名に応じて、適切に読み替えてください。
interactive 問題を解くには、ターミナルを使うべきです。interactive 問題対策として、ターミナルを使ってみましょう。

#!/usr/bin/python3
s = input()
print(s)

上記コードを実行し、その後「oyo」と入力してください。そうすれば、 main.py くんが oyo と返答してくれるはずです。およ~。

$ python3 main.py  # 入力待ち状態になります
oyo  # あなたが入力してくださいね💛
oyo  # main.py くんが出力してくれます

4. D. Swap Hats

group がかなり黒魔術になっていてすいません…

s = list(input().split())
t = list(input().split())
di = {}
for i in range(3):
    di[s[i]] = i
tot = 0
for i in range(3):
    tot += 3 ** i * di[t[i]]
group = [7, 11, 21]
print("Yes" if tot in group else "No")

5. C. Go Home

単調性があったので二分探索をしてしまった。「全ての提出」を見て気付いたが愚直が通る。

  • 二分探索: O(logn)O(\log \sqrt n)
  • 愚直: O(n)=O(104.5)O(\sqrt n) = O(10^{4.5}) (n=109\because n = 10^9)
x = int(input())
 
ng = 0
ok = int(1e5)
while ok - ng > 1:
    mid = (ok + ng) // 2
    if mid * (mid + 1) // 2 >= x:
        ok = mid
    else:
        ng = mid
print(ok)
int main() {
    using ll = long long;
    ll x;
    cin >> x;
    ll ng = -1, ok = 1e5;
    auto valid = [&](ll i) {
        return x <= i * (i + 1) / 2;
    };
    // めぐる式二分探索
    while (abs(ok - ng) > 1) {
        ll mid = (ok + ng) / 2;
        (valid(mid) ? ok : ng) = mid;
    }
    cout << ok << '\n';
    return 0;
}

6. D. Between Two Arrays

言われた通りの dp を書くと O(nmax(b)2)O(n \max(b)^2)
累積和で高速化して O(nmax(b))O(n \max(b))

#include <bits/stdc++.h>
using namespace std;

constexpr int MOD = 998244353;

template <int m>
struct Modular {
   private:
    uint _v;
    using mint = Modular;

   public:
    constexpr Modular() : _v(0) {}
    constexpr Modular(long long v) {
        v %= 1ll * m;
        _v = v < 0 ? v + m : v;
    };
    mint &operator++() {
        if (++_v == umod()) _v = 0;
        return *this;
    }
    mint &operator--() {
        if (_v == 0) _v = umod();
        return _v--, *this;
    }
    mint operator++(int) {
        mint res = *this;
        return ++*this, res;
    }
    mint operator--(int) {
        mint res = *this;
        return --*this, res;
    }
    constexpr mint operator-() { return mint() - *this; }
    mint operator+(const mint &rhs) { return mint(*this) += rhs; }
    mint operator-(const mint &rhs) { return mint(*this) -= rhs; }
    mint operator*(const mint &rhs) { return mint(*this) *= rhs; }
    mint operator/(const mint &rhs) { return mint(*this) /= rhs; }
    mint &operator+=(const mint &rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint &operator-=(const mint &rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint &operator*=(const mint &rhs) {
        _v = 1ll * _v * rhs._v % umod();
        return *this;
    }
    mint &operator/=(const mint &rhs) { return *this = *this * rhs.inv(); }
    friend mint operator+(const mint &lhs, const mint &rhs) { return mint(lhs) += rhs; }
    friend mint operator-(const mint &lhs, const mint &rhs) { return mint(lhs) -= rhs; }
    friend mint operator*(const mint &lhs, const mint &rhs) { return mint(lhs) *= rhs; }
    friend mint operator/(const mint &lhs, const mint &rhs) { return mint(lhs) /= rhs; }
    bool operator==(const mint &rhs) { return this->_v == rhs._v; }
    bool operator!=(const mint &rhs) { return this->_v != rhs._v; }
    static constexpr int mod() { return m; }
    constexpr uint val() const { return _v; }
    mint pow(long long n) const {
        mint x = *this, res = 1;
        while (n) {
            if (n & 1) res *= x;
            x *= x, n /= 2;
        }
        return res;
    }
    mint inv() const { return pow(umod() - 2); }
    friend istream &operator>>(istream &is, mint &x) {
        long long _v;
        return is >> _v, x = _v, is;
    }
    friend ostream& operator<<(ostream& os, const mint& x) { return os << x.val(); }

   private:
    static constexpr uint umod() { return m; }
};
using mint = Modular<MOD>;
constexpr mint operator""_M(unsigned long long x) { return mint(x); }

int main() {
    int n;
    cin >> n;
    vector<int> a(n), b(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> b[i];
    }
    const int MX = 3020;
    vector<mint> cur(MX, 0_M);
    cur[0] = 1_M;
    for (int i = 0; i < n; i++) {
        vector<mint> cur_acc(MX, 0_M);
        for (int j = 0; j < MX; j++) {
            cur_acc[j] = j ? cur_acc[j - 1] + cur[j] : cur[j];
        }
        vector<mint> nxt(MX, 0_M);
        for (int x = a[i]; x <= b[i]; x++) {
            nxt[x] = cur_acc[x];
        }
        swap(cur, nxt);
    }
    mint ans = 0_M;
    for (int i = 0; i < MX; i++) {
        ans += cur[i];
    }
    cout << ans << '\n';
    return 0;
}

7. E. King Bombee

自力 AC。制約がやけに小さいので愚直に違いない、と考えた。愚直でいいことに気付けば、愚直 dp するだけ。

#include <bits/stdc++.h>
using namespace std;

constexpr int MOD = 998244353;

template <int m>
struct Modular {
   private:
    uint _v;
    using mint = Modular;

   public:
    constexpr Modular() : _v(0) {}
    constexpr Modular(long long v) {
        v %= 1ll * m;
        _v = v < 0 ? v + m : v;
    };
    mint &operator++() {
        if (++_v == umod()) _v = 0;
        return *this;
    }
    mint &operator--() {
        if (_v == 0) _v = umod();
        return _v--, *this;
    }
    mint operator++(int) {
        mint res = *this;
        return ++*this, res;
    }
    mint operator--(int) {
        mint res = *this;
        return --*this, res;
    }
    constexpr mint operator-() { return mint() - *this; }
    mint operator+(const mint &rhs) { return mint(*this) += rhs; }
    mint operator-(const mint &rhs) { return mint(*this) -= rhs; }
    mint operator*(const mint &rhs) { return mint(*this) *= rhs; }
    mint operator/(const mint &rhs) { return mint(*this) /= rhs; }
    mint &operator+=(const mint &rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint &operator-=(const mint &rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint &operator*=(const mint &rhs) {
        _v = 1ll * _v * rhs._v % umod();
        return *this;
    }
    mint &operator/=(const mint &rhs) { return *this = *this * rhs.inv(); }
    friend mint operator+(const mint &lhs, const mint &rhs) { return mint(lhs) += rhs; }
    friend mint operator-(const mint &lhs, const mint &rhs) { return mint(lhs) -= rhs; }
    friend mint operator*(const mint &lhs, const mint &rhs) { return mint(lhs) *= rhs; }
    friend mint operator/(const mint &lhs, const mint &rhs) { return mint(lhs) /= rhs; }
    bool operator==(const mint &rhs) { return this->_v == rhs._v; }
    bool operator!=(const mint &rhs) { return this->_v != rhs._v; }
    static constexpr int mod() { return m; }
    constexpr uint val() const { return _v; }
    mint pow(long long n) const {
        mint x = *this, res = 1;
        while (n) {
            if (n & 1) res *= x;
            x *= x, n /= 2;
        }
        return res;
    }
    mint inv() const { return pow(umod() - 2); }
    friend istream &operator>>(istream &is, mint &x) {
        long long _v;
        return is >> _v, x = _v, is;
    }
    friend ostream& operator<<(ostream& os, const mint& x) { return os << x.val(); }

   private:
    static constexpr uint umod() { return m; }
};
using mint = Modular<MOD>;
constexpr mint operator""_M(unsigned long long x) { return mint(x); }

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n, m, k, s, t, x;
    cin >> n >> m >> k >> s >> t >> x;
    s--, t--, x--;
    vector<vector<int>> edges(n);
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b;
        edges[--a].push_back(--b);
        edges[b].push_back(a);
    }
    vector<vector<mint>> cur(2, vector<mint>(n, 0));
    cur[0][s] = 1;
    for (int _ = 0; _ < k; _++) {
        vector<vector<mint>> nxt(2, vector<mint>(n, 0));
        for (int v1 = 0; v1 < n; v1++) {
            for (auto v2 : edges[v1]) {
                for (int bit = 0; bit < 2; bit++) {
                    nxt[bit ^ (v2 == x)][v2] += cur[bit][v1];
                }
            }
        }
        swap(cur, nxt);
    }
    mint ans = cur[0][t];
    cout << ans << '\n';
    return 0;
}

8. D. Anything Goes to Zero

snuke さんの解説見ました。mod の値が s_pcnt ± 1 の 2 種にしかならないことに気付けば、綺麗に差分更新できる。コーナーケースに注意する。

#include <bits/stdc++.h>
using namespace std;

template <class T>
T modpow(T x, T n, T m) {
    x %= m;
    T res = 1;
    while (n) {
        if (n & 1) res = res * x % m;
        x = x * x % m;
        n /= 2;
    }
    return res;
}
int main() {
    using ll = long long;
    ll n;
    string s;
    cin >> n >> s;
    ll s_pcnt = 0;
    for (int i = 0; i < n; i++) {
        if (s[i] == '1') s_pcnt++;
    }
    vector<ll> tot_base(2);
    for (int adds = 0; adds < 2; adds++) {
        ll mod = adds ? s_pcnt + 1 : s_pcnt - 1;
        if (mod <= 0) continue;
        for (int i = 0; i < n; i++) {
            tot_base[adds] = (tot_base[adds] * 2 + (s[i] == '1')) % mod;
        }
    }
    auto parse = [&](ll idx) -> ll {
        bool adds = s[idx] == '0';
        ll mod = adds ? s_pcnt + 1 : s_pcnt - 1;
        if (mod == 0) return -1;
        ll tot = 0;
        // tot_base から差分更新して tot を算出
        if (adds) {
            tot = (tot_base[adds] + modpow(2ll, n - 1 - idx, mod)) % mod;
        } else {
            tot = (tot_base[adds] - modpow(2ll, n - 1 - idx, mod) + mod) % mod;
        }
        return tot;
    };
    auto calc = [&](auto self, ll x) -> ll {
        if (!x) return 0ll;
        return self(self, x % __builtin_popcountll(x)) + 1;
    };
    for (int i = 0; i < n; i++) {
        ll x = parse(i);
        // コーナーケース
        if (x == -1) {
            cout << 0 << '\n';
            continue;
        }
        cout << calc(calc, x) + 1 << '\n';
    }
    return 0;
}
loading...