[Pertanyaan ini adalah tindak lanjut untuk Menghitung berjalannya string ]
Periode
p
stringw
adalah bilangan bulat positifp
sehinggaw[i]=w[i+p]
setiap kali kedua sisi persamaan ini didefinisikan. Biarkanper(w)
menunjukkan ukuran periode terkecilw
. Kami mengatakan bahwa stringw
adalah iff periodikper(w) <= |w|/2
.
Jadi secara informal string periodik hanyalah string yang dibuat dari string lain yang diulang setidaknya satu kali. Satu-satunya komplikasi adalah bahwa pada akhir string kita tidak memerlukan salinan penuh dari string yang diulang selama itu diulang secara keseluruhan setidaknya sekali.
Misalnya, perhatikan string x = abcab
. per(abcab) = 3
sebagai x[1] = x[1+3] = a
, x[2]=x[2+3] = b
dan tidak ada periode yang lebih kecil. abcab
Karenanya string tidak periodik. Namun, string tersebut ababa
adalah periodik sebagai per(ababa) = 2
.
Sebagai lebih banyak contoh abcabca
,, ababababa
dan abcabcabc
juga berkala.
Bagi mereka yang suka regex, yang ini mendeteksi apakah suatu string periodik atau tidak:
\b(\w*)(\w+\1)\2+\b
Tugasnya adalah untuk menemukan semua substring periodik maksimal dalam string yang lebih panjang. Ini kadang-kadang disebut run dalam literatur.
Substring
w
adalah substring periodik maksimal (run) jika periodik dan tidakw[i-1] = w[i-1+p]
jugaw[j+1] = w[j+1-p]
. Secara informal, "jalankan" tidak dapat dimuat dalam "lari" yang lebih besar dengan periode yang sama.
Karena dua run dapat mewakili string karakter yang sama yang terjadi di tempat yang berbeda di string keseluruhan, kami akan mewakili run dengan interval. Berikut adalah definisi di atas yang diulang dalam hal interval.
Suatu run (atau substring periodik maksimal) dalam suatu string
T
adalah suatu interval[i...j]
denganj>=i
, sedemikian rupa sehingga
T[i...j]
adalah kata periodik dengan titikp = per(T[i...j])
- Itu maksimal. Secara formal, tidak
T[i-1] = T[i-1+p]
jugaT[j+1] = T[j+1-p]
. Secara informal, proses tidak dapat dimuat dalam proses yang lebih besar dengan periode yang sama.
Ditunjukkan oleh RUNS(T)
set run dalam string T
.
Contoh menjalankan
Keempat substring periodik maksimal (berjalan) dalam string
T = atattatt
adalahT[4,5] = tt
,T[7,8] = tt
,T[1,4] = atat
,T[2,8] = tattatt
.String
T = aabaabaaaacaacac
berisi berikut 7 substring periodik maksimal (berjalan):T[1,2] = aa
,T[4,5] = aa
,T[7,10] = aaaa
,T[12,13] = aa
,T[13,16] = acac
,T[1,8] = aabaabaa
,T[9,15] = aacaaca
.String
T = atatbatatb
berisi tiga run berikut. Mereka adalah:T[1, 4] = atat
,T[6, 9] = atat
danT[1, 10] = atatbatatb
.
Di sini saya menggunakan pengindeksan 1.
Tugas
Tulis kode sehingga untuk setiap bilangan bulat n mulai dari 2, Anda menghasilkan jumlah run terbanyak yang terkandung dalam string biner panjang mana pun n
.
Skor
Skor Anda adalah yang tertinggi yang n
Anda capai dalam 120 detik sehingga untuk semua k <= n
, tidak ada orang lain yang memposting jawaban yang benar lebih tinggi dari Anda. Jelas jika Anda memiliki semua jawaban optimal maka Anda akan mendapatkan skor untuk tertinggi yang n
Anda posting. Namun, meskipun jawaban Anda tidak optimal, Anda masih bisa mendapatkan skor jika tidak ada orang lain yang bisa mengalahkannya.
Bahasa dan perpustakaan
Anda dapat menggunakan bahasa dan perpustakaan yang tersedia yang Anda suka. Jika memungkinkan, alangkah baiknya untuk dapat menjalankan kode Anda, jadi harap sertakan penjelasan lengkap tentang cara menjalankan / kompilasi kode Anda di Linux jika memungkinkan.
Contoh optima
Berikut ini: n, optimum number of runs, example string
.
2 1 00
3 1 000
4 2 0011
5 2 00011
6 3 001001
7 4 0010011
8 5 00110011
9 5 000110011
10 6 0010011001
11 7 00100110011
12 8 001001100100
13 8 0001001100100
14 10 00100110010011
15 10 000100110010011
16 11 0010011001001100
17 12 00100101101001011
18 13 001001100100110011
19 14 0010011001001100100
20 15 00101001011010010100
21 15 000101001011010010100
22 16 0010010100101101001011
Apa sebenarnya yang harus saya hasilkan kode?
Untuk setiap n
kode Anda harus menampilkan string tunggal dan jumlah berjalan di dalamnya.
Mesin Saya Pengaturan waktu akan dijalankan pada mesin saya. Ini adalah instalasi ubuntu standar pada Prosesor Delapan Core AMD FX-8350. Ini juga berarti saya harus dapat menjalankan kode Anda.
Memimpin jawaban
- 49 oleh Anders Kaseorg di C . Single berulir dan jalankan dengan L = 12 (2GB RAM).
- 27 oleh cdlane di C .
sumber
{0,1}
-string, harap nyatakan secara eksplisit. Kalau tidak, alfabet mungkin tak terbatas, dan saya tidak melihat mengapa testcases Anda harus optimal, karena sepertinya Anda hanya mencari{0,1}
string juga.n
hingga12
dan tidak pernah mengalahkan alfabet biner. Secara heuristik saya berharap bahwa string biner harus optimal, karena menambahkan lebih banyak karakter akan meningkatkan panjang minimum run.Jawaban:
C
Ini melakukan pencarian rekursif untuk solusi optimal, dipangkas berat menggunakan batas atas pada jumlah run yang dapat diselesaikan oleh sisa string yang tidak diketahui. Perhitungan batas atas menggunakan tabel pencarian raksasa yang ukurannya dikontrol oleh konstanta
L
(L=11
: 0,5 GiB,:L=12
2 GiB,:L=13
8 GiB).Di laptop saya, ini naik melalui n = 50 dalam 100 detik; baris berikutnya muncul di 142 detik.
Keluaran:
Berikut adalah semua urutan optimal untuk n ≤ 64 (bukan hanya leksikografis pertama), yang dihasilkan oleh versi modifikasi dari program ini dan banyak jam perhitungan.
Urutan hampir optimal yang luar biasa
Awalan dari urutan fraktal tak terbatas
yang tidak berubah di bawah transformasi 101 ↦ 10100, 00 ↦ 101:
tampaknya memiliki jumlah run yang sangat optimal — selalu dalam 2 dari optimal untuk n ≤ 64. Jumlah run dalam karakter n pertama dibagi dengan pendekatan n (13 - 5√5) / 2 ≈ 0,90983. Tetapi ternyata ini bukan rasio yang optimal — lihat komentar.
sumber
Karena ini bukan perlombaan jika hanya ada satu kuda, saya mengirimkan solusi saya meskipun itu hanya sebagian kecil dari kecepatan Anders Kaseorg dan hanya sepertiga sebagai samar. Kompilasi dengan:
Inti dari algoritma saya adalah perubahan sederhana dan skema XOR:
Jalankan angka nol dalam hasil XOR yang lebih besar dari atau sama dengan periode / shift saat ini menunjukkan menjalankan dalam string asli untuk periode ini. Dari sini Anda bisa mengetahui berapa lama proses itu dan di mana ia mulai dan berakhir. Sisa kode adalah overhead, mengatur situasi dan mendekode hasilnya.
Saya berharap ini akan menghasilkan setidaknya 28 setelah dua menit pada mesin Lembik. (Saya menulis versi pthread, tetapi hanya berhasil membuatnya berjalan lebih lambat.)
Keluaran:
sumber
-O3
tidak dimaksudkan sebagai "tidak aman". Ini memungkinkan auto-vectorization, tetapi mungkin tidak ada yang di-vectorize di sini. Kadang-kadang dapat membuat kode lebih lambat, misalnya jika menggunakan cmov tanpa cabang untuk sesuatu di mana cabang akan diprediksi dengan sangat baik. Tetapi biasanya itu akan membantu. Biasanya patut dicoba juga, untuk melihat mana dari gcc atau dentang membuat kode yang lebih baik untuk loop tertentu. Juga, hampir selalu membantu untuk digunakan-march=native
, atau setidaknya-mtune=native
jika Anda masih menginginkan biner yang berjalan di mana saja.