Anda diberi kisaran besar [a, b] di mana 'a' dan 'b' biasanya antara 1 dan 4,000,000,000 inklusif. Anda harus mencari XOR dari semua angka dalam rentang yang diberikan.
Masalah ini digunakan di TopCoder SRM. Saya melihat salah satu solusi yang dikirimkan dalam pertandingan dan saya tidak dapat mengetahui cara kerjanya.
Bisakah seseorang membantu menjelaskan solusi pemenang:
long long f(long long a) {
long long res[] = {a,1,a+1,0};
return res[a%4];
}
long long getXor(long long a, long long b) {
return f(b)^f(a-1);
}
Di sini, getXor()
adalah fungsi sebenarnya untuk menghitung xor dari semua bilangan dalam rentang yang dilewati [a, b] dan "f ()" adalah fungsi pembantu.
a<=0
, atau untukb<0
.long long
adalah tipe bertanda, begitux%4
juga negatif (atau 0) untuk input negatif . Mungkin Anda inginunsigned long long
, dan / ataua & 3
mengindeks array?Jawaban:
Ini adalah solusi yang cukup pintar - ini mengeksploitasi fakta bahwa ada pola hasil dalam XOR yang sedang berjalan. The
f()
Fungsi menghitung XOR total run dari [0, a]. Lihat tabel ini untuk angka 4-bit:Dimana kolom pertama adalah representasi biner dan kemudian hasil desimal dan hubungannya dengan indeksnya (a) ke dalam daftar XOR. Ini terjadi karena semua bit atas dibatalkan dan dua bit terendah berputar setiap 4. Jadi, begitulah cara sampai ke tabel pencarian kecil itu.
Sekarang, pertimbangkan rentang umum [a, b]. Kita bisa menggunakan
f()
XOR untuk [0, a-1] dan [0, b]. Karena setiap nilai XOR dengan dirinya sendiri adalah nol,f(a-1)
just membatalkan semua nilai dalam XOR berjalan kurang daria
, meninggalkan Anda dengan XOR dari rentang [a, b].sumber
a
ada 2, bukan 0.Menambahkan jawaban bagus FatalError, kalimat
return f(b)^f(a-1);
itu bisa dijelaskan dengan lebih baik. Singkatnya, itu karena XOR memiliki properti luar biasa ini:Inilah keduanya beraksi:
Seperti ini:
Tambah dan perkalian adalah dua contoh operator asosiatif / komutatif lainnya, tetapi mereka tidak membalikkan dirinya sendiri. Oke, jadi, mengapa properti ini penting? Cara yang sederhana adalah mengembangkannya menjadi apa adanya, dan kemudian Anda dapat melihat properti ini bekerja.
Pertama, mari kita tentukan apa yang kita inginkan dan beri nama n:
Jika membantu, pikirkan XOR (^) seolah-olah itu adalah tambahan.
Mari kita juga mendefinisikan fungsinya:
b
lebih besar daria
, jadi hanya dengan memasukkan beberapa tanda kurung ekstra dengan aman (yang dapat kami lakukan karena ini asosiatif), kami juga dapat mengatakan ini:Yang disederhanakan menjadi:
Selanjutnya, kami menggunakan properti pembalikan dan komutivitas untuk memberi kami garis ajaib:
Jika Anda menganggap XOR seperti penjumlahan, Anda akan mengurangi pengurangan di sana. XOR adalah untuk XOR apa menambahkan untuk mengurangi!
Bagaimana saya mendapatkan ini sendiri?
Ingat properti operator logika. Bekerja dengan mereka hampir seperti menambah atau mengalikan jika itu membantu. Rasanya tidak biasa bahwa dan (&), xor (^) dan atau (|) adalah asosiatif, padahal memang demikian!
Jalankan implementasi naif melalui pertama, cari pola dalam output, lalu mulai temukan aturan yang mengonfirmasi bahwa pola tersebut benar. Sederhanakan penerapan Anda lebih jauh dan ulangi. Ini mungkin rute yang diambil oleh pembuat aslinya, disorot oleh fakta bahwa itu tidak sepenuhnya optimal (yaitu gunakan pernyataan switch daripada array).
sumber
Saya menemukan bahwa kode di bawah ini juga berfungsi seperti solusi yang diberikan dalam pertanyaan.
Mungkin ini sedikit dioptimalkan tetapi itu hanya apa yang saya dapatkan dari mengamati pengulangan seperti yang diberikan dalam jawaban yang diterima,
Saya ingin mengetahui / memahami bukti matematika di balik kode yang diberikan, seperti yang dijelaskan dalam jawaban oleh @ Luke Briggs
Ini kode JAVA itu
sumber
Saya telah memecahkan masalah dengan rekursi. Saya hanya membagi dataset menjadi bagian yang hampir sama untuk setiap iterasi.
Beri tahu saya pendapat Anda tentang solusinya. Senang mendapatkan masukan perbaikan. Solusi yang diusulkan menghitung XOR dalam kompleksitas 0 (log N).
Terima kasih
sumber
Untuk mendukung XOR dari 0 ke N kode yang diberikan perlu dimodifikasi seperti di bawah ini,
sumber