Kontes berakhir bukan berarti pembelajaran berhenti. Justru fase evaluasi solusi — membaca editorial, mengimplementasi ulang, dan merefleksikan kesalahan — adalah tempat peningkatan kemampuan terbesar terjadi. Pada Chapter ini kita akan membahas kerangka evaluasi yang sistematis: apa yang harus dibaca, apa yang harus ditulis ulang, dan bagaimana mengukur kemajuan dari kontes ke kontes.

Mengapa Evaluasi Pasca-Kontes Penting #

Banyak peserta kontes hanya fokus pada saat kontes berlangsung dan langsung pindah ke kontes berikutnya tanpa refleksi. Kebiasaan ini membuat kesalahan yang sama diulang terus-menerus. Sebaliknya, evaluasi pasca-kontes memungkinkan kita:

  • Mengidentifikasi pola kesalahan yang berulang (mis. lupa long long, salah kompleksitas).
  • Mempelajari teknik baru dari soal yang tidak bisa kita selesaikan.
  • Membangun intuisi tentang soal yang sebenarnya bisa kita kerjakan dengan usaha lebih.
  • Mengukur apakah kita benar-benar memahami konsep atau hanya menghafal.

Membaca Editorial dengan Benar #

Editorial bukan sekadar jawaban yang harus disalin. Editorial adalah penjelasan cara berpikir yang harus kita pahami langkah demi langkah. Saat membaca editorial, hindari langsung melihat kode akhir. Lakukan secara bertahap:

  1. Baca deskripsi solusi tingkat tinggi (paragraf pertama editorial biasanya).
  2. Tutup editorial, coba implementasikan sendiri berdasarkan ide tersebut.
  3. Jika buntu, buka editorial bagian demi bagian (bukan langsung kode penuh).
  4. Bandingkan kode kita dengan kode editorial untuk menemukan perbedaan gaya.

Berikut contoh template log pembacaan editorial yang bisa kita pakai:

text
Kontes: Codeforces Round 1234
Soal: C - Maximum Subarray II
Sumber: https://codeforces.com/blog/...

Teknik utama: Sliding window + monotonic queue
Kompleksitas: O(n)

Catatan:
- Awalnya coba DP, TLE karena O(n^2).
- Editorial menunjukkan observasi: kita hanya peduli max dalam window.
- Implementasi ulang dengan deque: https://...
- Insight: monotonic queue dapat dipakai untuk sliding window min/max O(1) amortized.

Kesalahan saya: salah baca constraint, kira n <= 1000 ternyata 10^5.

Catatan seperti ini lebih berharga daripada sekadar “solved” atau “not solved”.

Upsolve: Implementasi Uang Solusi yang Belum Dikerjakan #

Upsolve adalah praktik mengerjakan soal yang tidak kita selesaikan selama kontes. Ini adalah aktivitas paling penting untuk meningkatkan rating. Tanpa upsolve, pengetahuan baru dari editorial tidak benar-benar tertanam.

Strategi upsolve yang efektif:

  • Kerjakan soal yang hampir kita selesaikan saat kontes (gap kecil).
  • Kerjakan satu atau dua soal di atas level kita saat ini (stretch goal).
  • Jangan terlalu ambisius — jika editorial tidak masuk akal setelah 30 menit, simpan untuk nanti.
  • Setelah berhasil, tulis ulang solusi tanpa lihat editorial untuk memverifikasi pemahaman.
cpp
#include <bits/stdc++.h>
using namespace std;

// Contoh template upsolve dengan komentar refleksi
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, k;
    cin >> n >> k;
    vector<long long> a(n);
    for (auto& x : a) cin >> x;

    // Teknik: sliding window max dengan monotonic deque
    // Kompleksitas: O(n) — jauh lebih baik dari DP O(n*k) yang awalnya saya coba
    deque<int> dq;
    for (int i = 0; i < n; ++i) {
        while (!dq.empty() && a[dq.back()] <= a[i]) dq.pop_back();
        dq.push_back(i);
        while (dq.front() <= i - k) dq.pop_front();
        if (i >= k - 1) cout << a[dq.front()] << ' ';
    }
    cout << '\n';
}

Output yang Dihasilkan (input 8 3 lalu 1 3 -1 5 2 8 -2 4):

text
3 5 5 8 8 8

Mari kita telaah bagian penting dari kode di atas:

  1. Baris deque<int> dq: deque menyimpan indeks elemen, bukan nilai. Ini memudahkan pengecekan posisi relatif terhadap window.
  2. Baris while (!dq.empty() && a[dq.back()] <= a[i]): keluarkan semua indeks yang nilai elemennya lebih kecil dari a[i], karena elemen-elemen itu tidak akan pernah menjadi max selama a[i] masih di window.
  3. Baris while (dq.front() <= i - k): buang indeks yang sudah keluar dari window kiri.
  4. Baris if (i >= k - 1): baru cetak setelah window pertama terbentuk penuh.

Refleksi Kesalahan Berulang #

Sebagian besar peserta memiliki pola kesalahan yang sama di banyak kontes. Tanpa refleksi terstruktur, kesalahan ini tidak akan pernah hilang. Buat tabel sederhana di spreadsheet atau Markdown:

text
Tanggal    | Kontes       | Soal | Kesalahan                  | Kategori
-----------|--------------|------|----------------------------|------------------
2024-03-01 | CF 1234      | B    | Lupa long long, overflow   | Tipe data
2024-03-08 | AtCoder 234  | C    | Off-by-one di batas loop   | Boundary
2024-03-15 | CF 1235      | A    | Lupa sync_with_stdio, TLE   | I/O
2024-03-22 | AtCoder 235   | D    | Salah estimasi kompleksitas| Analisis

Setelah beberapa minggu, pola akan muncul. Jika “Tipe data” muncul lima kali, tambahkan typedef long long ll; di template dan gunakan long long secara default untuk akumulasi.

Mengukur Kemajuan #

Rating adalah ukuran yang baik tetapi bervariasi karena kebetulan. Ukuran yang lebih stabil:

  • Persentase soal yang diselesaikan dalam kontes virtual dibandingkan kontes asli.
  • Waktu rata-rata untuk menyelesaikan soal A dan B (seharusnya menurun).
  • Jumlah soal upsolve per minggu (konsistensi lebih penting daripada volume).
  • Penguasaan teknik tertentu (mis. “saya sudah menyelesaikan 10 soal DP berturut-turut”).
cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    // Log latihan sederhana
    vector<tuple<string, string, string>> log = {
        {"2024-03-01", "CF-1234-B", "DP knapsack"},
        {"2024-03-02", "CF-1234-C", "Sliding window"},
        {"2024-03-05", "AT-234-C", "Segment tree"},
        {"2024-03-08", "CF-1235-A", "Two pointers"},
    };

    map<string, int> techniqueCount;
    for (const auto& [date, problem, technique] : log) {
        ++techniqueCount[technique];
    }

    cout << "Distribusi teknik yang dipelajari:\n";
    for (const auto& [technique, count] : techniqueCount) {
        cout << "  " << technique << ": " << count << " soal\n";
    }
}

Output yang Dihasilkan:

text
Distribusi teknik yang dipelajari:
  DP knapsack: 1 soal
  Segment tree: 1 soal
  Sliding window: 1 soal
  Two pointers: 1 soal

Log seperti ini membantu kita melihat apakah distribusi latihan seimbang atau ada teknik yang terbengkalai.

Membangun Daftar Soal Referensi #

Setelah beberapa bulan, kita akan memiliki koleksi soal yang pernah dikerjakan. Simpan sebagai daftar terurut berdasarkan teknik untuk memudahkan review:

text
## Sliding Window
- CF 1234-C (medium, 1600 rating)
- CF 1235-D (hard, 1900 rating)

## Dynamic Programming
- AT 234-C (medium, 1700 rating)
- CF 1236-E (hard, 2200 rating)
``>

Sebelum kontes yang fokus pada topik tertentu, review daftar tersebut untuk mengingat kembali pola yang sudah dipelajari.

> [!IMPORTANT]
> Konsistensi lebih penting daripada intensitas. Satu kontes per minggu dengan upsolve penuh lebih baik daripada lima kontes tanpa refleksi.

## Latihan

1. Pilih satu kontes terakhir yang Anda ikuti. Baca editorial satu soal yang tidak Anda selesaikan, lalu implementasikan ulang tanpa melihat kode editorial.
2. Buat tabel refleksi kesalahan untuk lima kontes terakhir Anda. Identifikasi pola kesalahan yang muncul setidaknya tiga kali.
3. Susun daftar lima teknik yang Anda paling sering temui di kontes. Untuk setiap teknik, simpan tautan ke dua soal referensi yang sudah Anda selesaikan.

Dengan evaluasi yang konsisten, setiap kontes menjadi sumber pembelajaran, bukan sekadar angka rating yang naik turun.