Soalnya dapat Anda temui di web TLX: https://tlx.toki.id/problems/joints-2019-pcs-penyisihan
Sangat dianjurkan bagi Anda untuk mencobanya terlebih dahulu. Kalau tersendat baru liat pembahasan di sini :-)
Kode solusi saya cantumkan di akhir tulisan.
Dolan 2019
Deskripsi soal inilah yang membuat saya tertarik mengerjakan seluruh set soal.Cukup proses setiap barisnya satu per satu sambil mencatat kategori jawaban terbaik sejauh ini. Supaya mudah, kodekan kategori jawaban sebagai berikut:
0. BALIK AJA
1. TERPAKSA
2. SENANG
Awalnya inisialisasi kategori jawaban dengan 0 (untuk "BALIK AJA"). Untuk setiap baris, lakukan iterasi dari kiri ke kanan sambil mencatat:
- Karakter terakhir sebelum 'O'. Simpan karakter ini di variabel "prev".
- Banyaknya karakter 'O' konsekutif sampai sejauh ini. Anggap banyaknya ini disimpan di variabel "count".
Setiap kali ditemukan karakter yang bukan 'O', simpan karakter itu di variabel "next" dan periksa apakah:
Terakhir, tinggal cetak kategori jawaban terbaik. Kompleksitas solusinya O(RC).- count ≥ N+2. Kalau iya, berarti geng CJ pasti bisa "SENANG".
- count ≥ N+1. Kalau iya, periksa apakah salah satu dari prev atau next bernilai 'L'. Kalau iya berarti mereka "SENANG", dan kalau tidak berarti kategori 1 menjadi kandidat jawaban.
- count = N dan nilai dari prev dan next sama-sama 'L'. Kalau iya berarti "SENANG", dan kalau tidak berarti kategori 1 menjadi kandidat jawaban.
KPK
Solusi brutal jelas akan mendapat TLE, berhubung 3N dengan N=106 terlalu besar.Pertama, coba kita cari KPK dari suatu bilangan x dengan 3N. Kita dapat menyatakan x sebagai perkalian dari suatu bilangan k dengan 3p, sedemikian sehingga k tidak lagi mengandung faktor 3:
x=k3p
Mengingat masa SD, KPK dari k3p dan 3N adalah k3N.
Bila x dimulai dari 1 sampai dengan 3N, maka nilai yang ingin dicari adalah:
k13N+k23N+k33N+...+k3N3N=3N(k1+k2+k3+...+k3N)
Dengan kx menyatakan perkalian seluruh faktor x yang bukan 3.
Kini kita perlu mencari jumlahan barisan kx. Saya akan menyebut barisan ini dengan nama "barisan ampas" karena setiap elemennya seperti sisa bilangan setelah seluruh faktor 3-nya diperas habis.
Beberapa nilai pertama barisan ampas adalah:
1 2 1 4 5 2 7 8 1 10 11 4 13 14 5 ...Perhatikan bilangan yang tidak digaris bawah. Elemen di posisi bukan kelipatan 3 dijamin tidak berubah, karena mereka tidak mengandung faktor 3. Jumlahan elemen-elemen tersebut dapat dinyatakan dengan jumlah bilangan dari 1 sampai 3N, dikurangi dengan jumlah elemen di posisi kelipatan 3:
3N∑i=1i−33N−1∑i=1i
Sekarang kita tinggal menambahkannya dengan jumlahan bilangan-bilangan di posisi kelipatan 3. Coba kita kumpulkan nilainya dulu:
1 2 1 4 5 ...Ternyata ada pola yang berulang, nilai tersebut sama persis dengan barisan ampas. Perbedaannya hanya banyaknya elemen barisan ini adalah sepertiga sebelumnya, yakni 3N−1. Ini bukan kebetulan semata karena pembagian dari barisan 3, 6, 9, 12, 15, ... dengan 3 akan memunculkan 1, 2, 3, 4, 5, ...
Hal ini memberikan ide penyelesaian rekursif.
Apabila kita definisikan f(N) sebagai jumlahan barisan ampas pada awalnya, kini dapat dirumuskan:
f(N)=3N∑i=1i−33N−1∑i=1i+f(N−1)
Tetapkan base case-nya saat N=0, yang mana f(0)=1.
Untuk menghitung jumlah dari 1 sampai 3N secara cepat, gunakan rumus deret aritmetika:
3N∑i=1i=3N(3N+1)2
Sayangnya rumus ini tidak langsung dapat digunakan dengan modulo, karena ada pembagian dengan 2. Berhubung nilai modulonya dan 2 saling prima, kita dapat menggunakan invers modulo. Singkat cerita, perhitungannya menjadi:
3N∑i=1imodM=3N(3N+1)2M−2modM
(jangan lupa untuk mencari 2M−2 dengan pemangkatan fast exponentiation).
Sekarang tinggal menghitung nilai f dari 0 sampai dengan N seperti DP bottom up.
Setiap pertanyaan kini dapat dijawab dengan mencari 3Nf(N). Solusi ini bisa diimplementasikan dalam O(N).
Perpustakaan Blangkon
Soal sederhana kalau sudah tahu struktur data hash table atau BST. Cukup pakai unordered_map atau map pada C++. Kompleksitas solusi akhirnya O(N+M), dengan asumsi panjang judul buku tidaklah signifikan.Sepotong Batik
Bagian yang merepotkan dari soal ini adalah pola mungkin terpotong di atas, kiri, bawah, atau kanan.Untuk sedikit meringankan kerepotan, saya akan menambah seluruh koordinat dengan satu.
Lalu gunakan strategi 2D partial sum. Misalkan f(i,j) menyatakan banyaknya titik warna utama dari posisi (1,1) sampai (i,j). Mencari banyaknya titik warna dari (r1,c1) sampai dengan (r2,c2) sama dengan mencari:
f(r2,c2)−f(r2,c1−1)−f(r1−1,c2)+f(r1−1,c1−1)
Perhatikan ilustrasi berikut untuk jelasnya:
![]() |
Pencarian jumlahan elemen di (r1, c1) sampai (r2, c2) dengan 2D partial sum. |
Pencarian banyaknya titik warna dapat dipecah menjadi beberapa langkah:
- Buang semua jarak antar pola (vertikal maupun horizontal). Misalkan kini banyaknya baris dan kolom adalah rClean dan cClean.
- Hitung banyaknya baris yang sepenuhnya mengandung pola (tanpa peduli apakah ada pola terpotong di kanannya).
- Lakukan iterasi i=1 sampai dengan A, dan hitung banyaknya titik warna di posisi (i, 1) sampai dengan (i, cClean). Kalikan jawabannya dengan banyaknya baris yang sepenuhnya mengandung pola.
- Untuk pola yang terpotong di bawah, iterasi i=1 sampai dengan rClean%A, dan hitung banyaknya titik warna di posisi (i, 1) sampai dengan (i, cClean).
Dengan cara ini, fungsi f dapat dihitung dalam O(A).
Sangat cukup untuk mendapatkan accepted.
Komentar
Soal favorit saya adalah KPK, dan saya rasa ada solusinya yang lebih mudah. Kalau Anda tahu, mohon beritahu saya.Sentuhan akhir yang saya sarankan adalah penyeragaman format soal. Pada set soal ini, ada soal formatnya multicase dan menggunakan prefix "Kasus #x: ...", sementara soal lainnya tidak. Meskipun rasanya kurang penting untuk menyamakan formatnya, menurut saya ini akan memberikan kesan lebih artistik.
Seluruh kode solusi dapat diunduh di sini.
Saya akan membahas pembahasan semifinal pada tulisan mendatang.
izin bertanya kak soal KPK yang barisan "ampas" bagian tidak diberi garis bawah saya mendapatkan hasil berbeda sigma(i=1,3^n)i - sigma(i=1, 3^(n-1))3i, jadi rumus akhirnya berbeda dari diatas apakah ada kesalahan dalam perhitungan saya mohon pencerahanya kak, salam saya dari IF ITB 2014
BalasHapushalo, "sigma(i=1, 3^(n-1))3i" dan "3*sigma(i=1, 3^(n-1))i" itu sama saja. Rumus yang saya tulis kurang lengkap, jadi sekarang saya lengkapi. Terima kasih atas pertanyaannya
Hapus