ruby, cukup cepat, tetapi itu tergantung pada input
Sekarang percepat dengan faktor 2 ~ 2.5 dengan beralih dari string ke integer.
Pemakaian:
cat <input> | ruby this.script.rb
Misalnya.
mad_gaksha@madlab ~/tmp $ ruby c50138.rb < c50138.inp2
number of matches: 298208861472
took 0.05726237 s
Jumlah kecocokan untuk masker tunggal mudah dihitung dengan koefisien binomial. Jadi misalnya 122020
kebutuhan 3 2
s diisi, 1 0
dan 2 1
. Jadi ada nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3
beberapa string biner yang cocok dengan topeng ini.
Persimpangan antara n mask m_1, m_2, ... m_n adalah mask q, sehingga string biner s cocok dengan q hanya jika jika cocok dengan semua mask m_i.
Jika kita mengambil dua topeng m_1 dan m_2, persimpangannya mudah dihitung. Cukup atur m_1 [i] = m_2 [i] jika m_1 [i] == 2. Persimpangan antara 122020
dan 111222
adalah 111020
:
122020 (matched by 3 strings, 111000 110010 101010)
111222 (matched by 1 string, 111000)
111020 (matched by 1 string, 111000)
Dua topeng individu dicocokkan oleh 3 + 1 = 4 string, topeng intereseksi dicocokkan oleh satu string, sehingga ada 3 + 1-1 = 3 string unik yang cocok dengan satu atau kedua topeng.
Saya akan menelepon N (m_1, m_2, ...) jumlah string yang cocok dengan semua m_i. Dengan menerapkan logika yang sama seperti di atas, kita dapat menghitung jumlah string unik yang cocok dengan setidaknya satu topeng, yang diberikan oleh prinsip pengecualian inklusi dan lihat di bawah juga, seperti ini:
N(m_1) + N(m_2) + ... + N(m_n) - N(m_1,m_2) - ... - N(m_n-1,m_n) + N(m_1,m_2,m_3) + N(m_1,m_2,m_4) + ... N(m_n-2,m_n-1,m_n) - N(m_1,m_2,m_3,m_4) -+ ...
Ada banyak, banyak, banyak kombinasi pengambilan, misalnya 30 topeng dari 200.
Jadi solusi ini membuat asumsi bahwa tidak banyak persimpangan tingkat tinggi dari masker input, yaitu. kebanyakan n-tupel dari n> 2 topeng tidak akan memiliki kecocokan umum.
Gunakan kode di sini, kode di ideone mungkin kedaluwarsa.
Saya menambahkan fungsi remove_duplicates
yang dapat digunakan untuk pra-proses input dan menghapus topeng m_i
sehingga semua string yang cocok juga cocok dengan topeng lain m_j
., Untuk input saat ini, ini sebenarnya membutuhkan waktu lebih lama karena tidak ada topeng seperti itu (atau tidak banyak) , jadi fungsinya belum diterapkan ke data dalam kode di bawah ini.
Kode:
# factorial table
FAC = [1]
def gen_fac(n)
n.times do |i|
FAC << FAC[i]*(i+1)
end
end
# generates a mask such that it is matched by each string that matches m and n
def diff_mask(m,n)
(0..m.size-1).map do |i|
c1 = m[i]
c2 = n[i]
c1^c2==1 ? break : c1&c2
end
end
# counts the number of possible balanced strings matching the mask
def count_mask(m)
n = m.size/2
c0 = n-m.count(0)
c1 = n-m.count(1)
if c0<0 || c1<0
0
else
FAC[c0+c1]/(FAC[c0]*FAC[c1])
end
end
# removes masks contained in another
def remove_duplicates(m)
m.each do |x|
s = x.join
m.delete_if do |y|
r = /\A#{s.gsub(?3,?.)}\Z/
(!x.equal?(y) && y =~ r) ? true : false
end
end
end
#intersection masks of cn masks from m.size masks
def mask_diff_combinations(m,n=1,s=m.size,diff1=[3]*m[0].size,j=-1,&b)
(j+1..s-1).each do |i|
diff2 = diff_mask(diff1,m[i])
if diff2
mask_diff_combinations(m,n+1,s,diff2,i,&b) if n<s
yield diff2,n
end
end
end
# counts the number of balanced strings matched by at least one mask
def count_n_masks(m)
sum = 0
mask_diff_combinations(m) do |mask,i|
sum += i%2==1 ? count_mask(mask) : -count_mask(mask)
end
sum
end
time = Time.now
# parse input
d = STDIN.each_line.map do |line|
line.chomp.strip.gsub('2','3')
end
d.delete_if(&:empty?)
d.shift
d.map!{|x|x.chars.map(&:to_i)}
# generate factorial table
gen_fac([d.size,d[0].size].max+1)
# count masks
puts "number of matches: #{count_n_masks(d)}"
puts "took #{Time.now-time} s"
Ini disebut prinsip pengecualian inklusi, tetapi sebelum seseorang menunjuk saya ke sana, saya punya bukti sendiri, jadi begini saja. Melakukan sesuatu sendiri terasa hebat.
Mari kita perhatikan kasus 2 topeng, panggil dulu 0
dan 1
, pertama. Kami mengambil setiap string biner seimbang dan mengklasifikasikannya sesuai dengan topeng yang cocok. c0
adalah jumlah orang-orang yang cocok hanya topeng 0
, c1
nunber dari orang-orang yang cocok hanya 1
, c01
orang-orang yang cocok masker 0
dan 1
.
Membiarkan s0
menjadi jumlah jumlah dari jumlah kecocokan untuk setiap topeng (mereka mungkin tumpang tindih). Membiarkan s1
menjadi jumlah dari jumlah kecocokan untuk setiap pasangan (2-kombinasi) dari topeng. Biarkan s_i
menjadi jumlah dari jumlah kecocokan untuk setiap (i +1) kombinasi topeng. Jumlah kecocokan n-mask adalah jumlah string biner yang cocok dengan semua mask.
Jika ada n mask, output yang diinginkan adalah jumlah dari semua c
, yaitu. c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1)
. Apa yang dihitung program adalah jumlah bolak - balik dari semua s
, yaitu. s = s_0-s_1+s_2-+...+-s_(n-1)
. Kami ingin membuktikannya s==c
.
n = 1 jelas. Pertimbangkan n = 2. Menghitung semua pertandingan topeng 0
memberikan c0+c01
(jumlah string yang cocok hanya 0 + mereka cocok baik 0
dan 1
), menghitung semua pertandingan 1
memberikan c1+c02
. Kita dapat menggambarkan ini sebagai berikut:
0: c0 c01
1: c1 c10
Menurut definisi s0 = c0 + c1 + c12
,. s1
adalah jumlah jumlah kecocokan dari setiap 2 kombinasi [0,1]
, yaitu. semua uniqye c_ij
s. Ingat itu c01=c10
.
s0 = c0 + c1 + 2 c01
s1 = c01
s = s0 - s1 = c0 + c1 + c01 = c
Jadi s=c
untuk n = 2.
Sekarang pertimbangkan n = 3.
0 : c0 + c01 + c02 + c012
1 : c1 + c01 + c12 + c012
2 : c2 + c12 + c02 + c012
01 : c01 + c012
02 : c02 + c012
12 : c12 + c012
012: c012
s0 = c0 + c1 + c2 + 2 (c01+c02+c03) + 3 c012
s1 = c01 + c02 + c12 + 3 c012
s2 = c012
s0 = c__0 + 2 c__1 + 3 c__2
s1 = c__1 + 3 c__2
s2 = c__2
s = s0 - s1 + s2 = ... = c0 + c1 + c2 + c01 + c02 + c03 + c012 = c__0 + c__1 + c__2 = c
Jadi s=c
untuk n = 3. c__i
mewakili semua dari c
s dengan indeks (i +1), misalnya c__1 = c01
untuk n = 2 dan c__1 = c01 + c02 + c12
untuk n == 3.
Untuk n = 4, sebuah pola mulai muncul:
0: c0 + c01 + c02 + c03 + c012 + c013 + c023 + c0123
1: c1 + c01 + c12 + c13 + c102 + c103 + c123 + c0123
2: c2 + c02 + c12 + c23 + c201 + c203 + c213 + c0123
3: c3 + c03 + c13 + c23 + c301 + c302 + c312 + c0123
01: c01 + c012 + c013 + c0123
02: c02 + c012 + c023 + c0123
03: c03 + c013 + c023 + c0123
12: c11 + c012 + c123 + c0123
13: c13 + c013 + c123 + c0123
23: c23 + c023 + c123 + c0123
012: c012 + c0123
013: c013 + c0123
023: c023 + c0123
123: c123 + c0123
0123: c0123
s0 = c__0 + 2 c__1 + 3 c__2 + 4 c__3
s1 = c__1 + 3 c__2 + 6 c__3
s2 = c__2 + 4 c__3
s3 = c__3
s = s0 - s1 + s2 - s3 = c__0 + c__1 + c__2 + c__3 = c
Jadi s==c
untuk n = 4.
Secara umum, kita mendapatkan koefisien binomial seperti ini (↓ is i, → is j):
0 1 2 3 4 5 6 . . .
0 1 2 3 4 5 6 7 . . .
1 1 3 6 10 15 21 . . .
2 1 4 10 20 35 . . .
3 1 5 15 35 . . .
4 1 6 21 . . .
5 1 7 . . .
6 1 . . .
. .
. .
. .
Untuk melihat ini, pertimbangkan itu untuk beberapa i
dan j
, ada:
- x = ncr (n, i + 1): kombinasi C untuk persimpangan dari (i + 1) topeng dari n
- y = ncr (ni-1, ji): untuk setiap kombinasi C di atas, ada y kombinasi yang berbeda untuk persimpangan (j + 2) topeng dari yang mengandung C
- z = ncr (n, j + 1): kombinasi berbeda untuk persimpangan (j + 1) topeng dari n
Karena itu mungkin terdengar membingungkan, inilah definisi yang diterapkan pada contoh. Untuk i = 1, j = 2, n = 4, terlihat seperti ini (lih. Di atas):
01: c01 + c012 + c013 + c0123
02: c02 + c012 + c023 + c0123
03: c03 + c013 + c023 + c0123
12: c11 + c012 + c123 + c0123
13: c13 + c013 + c123 + c0123
23: c23 + c023 + c123 + c0123
Jadi di sini x = 6 (01, 02, 03, 12, 13, 23), y = 2 (dua c dengan tiga indeks untuk setiap kombinasi), z = 4 (c012, c013, c023, c023, c123).
Secara total, ada x*y
koefisien c
dengan indeks (j + 1), dan ada yang z
berbeda, sehingga masing-masing terjadi x*y/z
kali, yang kita sebut koefisien k_ij
. Dengan aljabar sederhana, kita dapatkan k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1)
.
Jadi indeks diberikan oleh k_ij = nCr(j+1,i+1)
Jika Anda mengingat semua definisi, yang perlu kita tunjukkan adalah bahwa jumlah bolak-balik dari setiap kolom menghasilkan 1.
Dengan s0 - s1 + s2 - s3 +- ... +- s(n-1)
demikian jumlah alternatif dapat dinyatakan sebagai:
s_j = c__j * ∑[(-1)^(i+j) k_ij] for i=0..n-1
= c__j * ∑[(-1)^(i+j) nCr(j+1,i+1)] for i=0..n-1
= c__j * ∑[(-1)^(i+j) nCr(j+1,i)]{i=0..n} - (-1)^0 nCr(j+1,0)
= (-1)^j c__j
s = ∑[(-1)^j s_j] for j = 0..n-1
= ∑[(-1)^j (-1)^j c__j)] for j=0..n-1
= ∑[c__j] for j=0..n-1
= c
Jadi s=c
untuk semua n = 1,2,3, ...