4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AtCoder C++リファレンス(茶コーダー向け)

Last updated at Posted at 2021-09-09

はじめに

茶コーダーが入緑するために習得中の知識をまとめています。
主にABC203以降に出題された問題と典型90問から習得しており、「出題」欄に出展を記載しています。

C問題

繰り返し二乗法(べき乗の高速計算)

int rep_pow(int_ a, int_ b) {
    if (b == 0) return 1;
    auto ans = rep_pow(a * a % m, b / 2);
    if (b % 2 == 1) ans = ans * a % m;
    return ans;
}

出題:ABC178, 典型069

見かけ上の変化をメモ

シフトや反転が複数回行われる場合、愚直な実装では計算量がオーバーする。

bool flip_flag = false;
rep (i, Q) {
    int t, a, b;
    cin >> t >> a >> b;
    if (t == 1) {
        if (flip_flag) swap(S[(a + N) % (2 * N)], S[(b + N) % (2 * N)]);
        else swap(S[a], S[b]);
    } else {
        flip_flag = !flip_flag;
    }
}

出題:ABC199, 典型044

数字文字列の0埋め

ostringstream sout;
sout << setfill('0') << setw(4) << i;
auto s = sout.str()

出題:ABC201

文字の数値化

atoi, stoiはstringをintに変換する関数であり、char型には対応していない。
(char*型には対応しているが、1文字ずつ数値化したい時に後続の文字も一緒に数値化されて困る)

auto number = int(ch-'0')

出題:ABC201, ABC221

二重ループを一重ループ2回に分解

unordered_map<int, int> counts;
rep (j, N) counts[B[C[j] - 1]]++;

int ans = 0;
rep (i, N) ans += counts[A[i]];

出題:ABC202

vector< pair >の入力とソート

一つ目の要素をkeyとしてソートされる

vector<pair<int_, int_>> seq(N);
for (auto& s: seq) cin >> s.first >> s.second;
sort(seq.begin(), seq.end());

出題:ABC203

vectorをある値で埋める

fill(seq.begin(), seq.end(), value)

出題:ABC204

DFS/BFS(行ける場所のカウント)

到着時刻を記録する必要はない。
flagsがそのまま、行ける場所のカウントに利用できる。

vector<vector<int>> roads_list;
vector<bool> flags;
void dfs(int s) {
    if (flags[s]) return;
    flags[s] = true;
    for (auto& v: roads_list[s]) dfs(v);
}
int main() {
    dfs(0);
    ans = count(flags.begin(), flags.end(), true);
}
void bfs(int s) {
    queue<int> q;
    q.push(s);
    flags[s] = true;
    while (!q.empty()) {
        auto v = q.front(); q.pop();
        // 全部キューに入れて通った場所の処理を飛ばすと
        // もっと簡単に書けるが、処理の無駄は多くなる
        for (auto& nv: roads_list[v]) if (!flags[nv]) {
            q.push(nv);
            flags[nv] = true;
        }
    }
}

出題:ABC204

argsort

vector<int> indices(N);
iota(indices.begin(), indices.end(), 0);  // 連番
stable_sort(indices.begin(), indices.end(), [&](int i, int j) {return seq[i] < seq[j];});

出題:ABC208

順位付け(argsortされたindicesに対する処理)

vector<int> ranks(N);
rep (i, N) ranks[indices[i]] = i;

出題:ABC208

連想配列(Pythonのdict)

// カウント
unordered_map<int, int> counts;
rep (i, N) counts[colors[i]]++; // keyは自動で追加、int型valueのデフォルト値は0
// 重複チェック
unordered_map<string, int> names;
rep (i, N) {
    string name;
    cin >> name;
    if (names[name] == 0) {
        cout << i + 1 << endl;
        names[name] = 1;
    }
}

出題:ABC202, ABC210, 典型027

座標圧縮

set<int> seq_set(seq.begin(), seq.end());
vector<int> uniq_seq(seq_set.begin(), seq_set.end());
for (auto& elem : seq) elem = lower_bound(uniq_seq.begin(), uniq_seq.end(), elem) - uniq_seq.begin();

出題:ABC213

argmin

int min_idx = distance(seq.begin(), min_element(seq.begin(), seq.end()));

出題:ABC214

順列生成

sort(seq.begin(), seq.end());
while (N > 0) {
    next_permutation(seq.begin(), seq.end());
    N--;
}
do {
    for (auto& c: seq) cout << c;
    cout << endl;
} while (next_permutation(seq.begin(), seq.end()));
vector<int> players(N);
iota(players.begin(), players.end(), 0);
int min_time = max_time;
do {
    int time = 0;
    rep (i, N - 1) time += times[players[i]][i];
    min_time = min(min_time, time);
} while (next_permutation(players.begin(), players.end()));

出題:ABC215, 典型002, 典型032

bit全探索

rep (bit, 1<<seq.size()) {
    rep (i, seq.size()) {
        if (bit & 1<<i) cout << "hoge";
    }
}

出題:ABC221

スワップ

配列内の要素も入れ替えられる。

swap(seq[p0], seq[p1);

出題:ABC199, ABC250

要素の位置の辞書

vector<ll> val(N+1), pos(N+1);
rep (i, N+1) val[i] = pos[i] = i;
rep (i, Q) {
    ll x;
    cin >> x;

    ll p0 = pos[x];
    ll p1 = p0 + 1;

    swap(pos[val[p0]], pos[val[p1]]);
    swap(val[p0], val[p1]);
}

出題:ABC250

順序付き多重集合

multiset<ll> seq;
rep (i, Q) {
    ll t;
    cin >> t;
    if (t == 1) {
        ll x;
        cin >> x;
        seq.insert(x);
    } else if (t == 2) {
        ll x, c;
        cin >> x >> c;
        while (c-- && seq.find(x) != seq.end()) {
            seq.erase(seq.find(x));
        }
    } else {
        cout << *seq.rbegin() - *seq.begin() << endl;
    }
}

出題:ABC253

D問題

deque(双方向連結リスト)

deque<char> deq;
rep (i, Q) {
    cin >> F >> c;
    if (F == 1) deq.push_front(c);
    else deq.push_back(c);
}

出題:ABC158, 典型061

累積和

vector<vector<int>> make_integral_img(vector<vector<int>> A, int_ th) {
    vector<vector<int>> S(N + 1, vector<int>(N + 1, 0));
    rep (i, N) rep (j, N) S[i + 1][j + 1] = S[i + 1][j] + S[i][j + 1] - S[i][j] + (A[i][j] >= th);
    return S;
}

bool isOK(vector<vector<int>> A, int th) {
    auto S = make_integral_img(A, th);
    rep (i, N - K + 1) {
        rep (j, N - K + 1) {
            if (S[i + K][j + K] - S[i + K][j] - S[i][j + K] + S[i][j] < K * K / 2 + 1) return false;
        }
    }
    return true;
}

出題:ABC203

(めぐる式)二分探索

int binary_search(vector<vector<int>> A) {
    int_ ok = 0;
    int_ ng = 1000000001;
    while (abs(ok - ng) > 1) {
        int_ mid = (ok + ng) / 2;
        if (isOK(A, mid)) ok = mid;
        else ng = mid;
    }
    return ok;
}

出題:ABC203, 典型001

部分和問題(01ナップサックの特殊ケース)

部分和問題は01ナップサックの重さと価値が同じケース。
公式動画解説では一次元化+bitset化してるが必須ではない。

vector<vector<int>> dp(N + 1, vector<int>(max_weight + 1, 0)); // 配列サイズ注意
rep (i, N) {
    rep (t, max_weight + 1) {
        if (weights[i] > t) dp[i + 1][t] = dp[i][t];
        // 01ナップサックだと最後のweights[i]がvalues[i]になる
        else dp[i + 1][t] = max(dp[i][t], dp[i][t - weights[i]] + weights[i]);
    }
}

出題:ABC204

二分探索

auto idx = upper_bound(seq.begin(), seq.end(), query) - seq.begin();
auto idx = distance(seq.begin(), upper_bound(seq.begin(), seq.end(), query));
auto iter = upper_bound(seq.begin(), seq.end(), query);

最初の要素より小さい場合と最後の要素より大きい場合に注意

rep (i, Q) {
    cin >> B;
    int diff;
    auto iter = upper_bound(classes.begin(), classes.end(), B);
    if (iter == classes.end()) diff = abs(*(classes.end() - 1) - B);
    else if (iter == classes.begin()) diff = abs(*classes.begin() - B);
    else diff = min(abs(*iter - B), abs(*(iter--) - B));
    cout << diff << endl;
}

出題:ABC205、典型007

BFS(最短距離)

distancesをflagsの代わりとして利用できる。

vector<int_> distances;
void bfs(int_ s) {
    queue<int_> q;
    q.push(s);
    distances[s] = 0;
    while (!q.empty()) {
        auto v = q.front(); q.pop();
        for (auto& nv: roads_list[v]) {
            if (distances[nv] == -1) {
                q.push(nv);
                distances[nv] = distances[v] + 1;
            }
        }
    }
}

出題:ABC209, 典型003(木の直径)

優先度付きキュー

priority_queue<int, vector<int>, greater<int>> pq;
rep (i, Q) {
    int p;
    cin >> p;
    if (p == 1) {
        int x;
        cin >> x;
        pq.push(x);
    } else {
        auto num = pq.top(); pq.pop();
        cout << num << endl;
    }
}

出題:ABC212

木のDFS

flag管理は不要、一つ前にいた場所を引数としてもらえばよい。
木を戻っていく順番まで記録するなど、木を前提にしないと解けないケースあり?

void dfs(int crr, int pre) {
    history.emplace_back(crr);
    for (auto& next: roads_list[crr]) if (next != pre) {
        dfs(next, crr);
        history.emplace_back(crr);
    }
}

出題:ABC213

sortのkey指定

key指定は面倒なので、keyにしたいものを最初の要素にしておく。

vector<tuple<int, int, int>> edge(N);
for (auto& [w, u, v] : edge) cin >> u >> v >> w;
sort(edge.begin(), edge.end());

出題:ABC214

UnionFind

#include <atcoder/dsu>
atcoder::dsu dsu(N);
int ans = 0;
for (auto& [w, u, v] : edges) {
    ans += w * dsu.size(u) * dsu.size(v);
    dsu.merge(u, v);
}
if (!dsu.same(a, b)) dsu.merge(a, b);

出題:ABC206, ABC214

素因数分解

vector<int> factorize(int elem) {
    vector<int> primes;
    for (int i = 2; i * i <= elem; i++) {
        while (elem % i == 0) {
            elem /= i;
            primes.emplace_back(i);
        }
    }
    if (elem != 1) primes.emplace_back(elem);
    return primes;
}

出題:ABC215, 典型075

順序付き集合

途中で挿入・削除したり、参照したりを繰り返す場合に使う(クエリに種類があるケースなど)。
途中で挿入・削除する必要が無いならvectorをsortして二分探索した方が速い。
Pythonのbisectも同様の処理が可能だが、setよりかなり遅くLTEする。

set<int> cuts;
rep (i, Q) {
    int_ c, x;
    cin >> c >> x;
    if (c == 1) cuts.insert(x);
    else {
        auto upper = cuts.lower_bound(x);
        cout << *upper - *(--upper) << endl;
    }
}
ll ans = 0;
ll max_score = 0;
rep (i, N) {
    string S;
    ll T;
    cin >> S >> T;
    auto result = originals.insert(S);
    if (result.second && (T > max_score)) {
        ans = i;
        max_score = T;
    }
}

出題:ABC217, ABC228, ABC251(C)

尺取り法

int_ ans = 0, r = 0;
rep (l, S.size()) {
    while(r < S.size() && cnt[r + 1] - cnt[l] <= K) r++;
    ans = max(ans, r - l);
}

出題:ABC229

4
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?