yakut, oldukça hızlı, ancak girdiye bağlı
Şimdi dizelerden tamsayılara geçerek 2 ~ 2,5 faktör hızlandırın.
Kullanımı:
cat <input> | ruby this.script.rb
Örneğin.
mad_gaksha@madlab ~/tmp $ ruby c50138.rb < c50138.inp2
number of matches: 298208861472
took 0.05726237 s
Binom katsayısı tarafından kolayca hesaplanan tek bir maske için eşleşme sayısı. Yani örneğin 1220203 2s dolu, 1 0ve 2 gerekir 1. Bu yüzden nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3bu maskeyle eşleşen farklı ikili dizeler vardır .
N maskeleri m_1, m_2, ... m_n arasındaki kesişme bir maske q'dur, öyle ki ikili bir s dizisi sadece m_i tüm maskelerle eşleştiğinde q ile eşleşir.
İki maske m_1 ve m_2 alırsak, kesişimi kolayca hesaplanır. M_1 [i] == 2 ise m_1 [i] = m_2 [i] ayarını yapmanız yeterlidir. Kesişme 122020ve 111222bir 111020:
122020 (matched by 3 strings, 111000 110010 101010)
111222 (matched by 1 string, 111000)
111020 (matched by 1 string, 111000)
İki ayrı maske 3 + 1 = 4 dize ile eşleştirilir, kesişim maskesi bir dize ile eşleştirilir, bu nedenle bir veya her iki maskle eşleşen 3 + 1-1 = 3 benzersiz dize vardır.
Tüm m_i ile eşleşen dizelerin sayısını N (m_1, m_2, ...) olarak arayacağım. Yukarıdaki ile aynı mantığı uygulayarak, dahil etme hariç tutma ilkesi tarafından verilen en az bir maske ile eşleşen benzersiz dizelerin sayısını hesaplayabilir ve aşağıdaki gibi de görebilirsiniz:
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) -+ ...
200'den 30 maske almanın birçok, birçok, birçok kombinasyonları var.
Böylece bu çözüm, giriş maskelerinin pek çok üst düzey kesişiminin olmadığı varsayımını yapar. n> 2 maskesinin çoğu n-tuplesinde ortak bir eşleşme olmaz.
Buradaki kodu kullanın, ideone'deki kod eski olabilir.
remove_duplicatesGiriş işlemek ve m_ionunla eşleşen tüm dizeleri de başka bir maske ile eşleşecek şekilde maskeleri silmek için kullanılabilecek bir işlev ekledim m_j., Geçerli giriş için, bu tür maskeler (veya çok fazla) olmadığı için bu aslında daha uzun sürer , bu nedenle işlev henüz aşağıdaki koddaki verilere uygulanmaz.
Kod:
# 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"
Buna dahil etme dışlama ilkesi denir, ancak biri beni işaret etmeden önce kendi kanıtım vardı, işte gidiyor. Kendiniz bir şey yapmak harika hissettiriyor.
İki maskeyi ele alalım, sonra arayın 0ve 1önce. Her dengeli ikili dizeyi alıp, hangi maskeye (maskelere) uygun olduğunu sınıflandırıyoruz. c0maske sadece maç olanların sayısıdır 0, c1sadece maç olanların Nunber 1, c01bu o maç maske 0ve 1.
Izin vermek s0her maske için maç sayısı toplamı (onlar örtüşebilir). Izin vermek s1her çifti (2-kombinasyonu) için eşleşme sayısı toplamı maskeleri. Izin vermek s_iher (i + 1) maske kombinasyonu için maç sayısı toplamı. N maskelerinin eşleşme sayısı, tüm maskelerle eşleşen ikili dizelerin sayısıdır.
Eğer n maske varsa, istenen çıktı tümünün toplamıdır c, yani. c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1). Programın hesapladığı şey, hepsinin alternatif toplamıdır s. s = s_0-s_1+s_2-+...+-s_(n-1). Bunu kanıtlamak istiyoruz s==c.
n = 1 açıktır. N = 2'yi düşünün. Maskenin tüm eşleşmeleri Sayma 0verir c0+c01(sadece 0 + olanlar eşleştirme hem eşleşen dizeleri sayısını 0ve 1her eşleşmeleri sayarak,) 1verir c1+c02. Bunu şu şekilde açıklayabiliriz:
0: c0 c01
1: c1 c10
Tanımı gereği s0 = c0 + c1 + c12,. s1her 2 kombinasyonunun toplam eşleşme sayısıdır [0,1], yani. tüm uniqye c_ijs. Unutmayın c01=c10.
s0 = c0 + c1 + 2 c01
s1 = c01
s = s0 - s1 = c0 + c1 + c01 = c
Böylece s=cn = 2 için.
Şimdi n = 3'ü düşünün.
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
Böylece s=cn = 3 için. (i + 1) indeksli c__itüm cs'leri temsil eder , örneğin c__1 = c01n = 2 ve c__1 = c01 + c02 + c12n == 3 için.
N = 4 için, bir desen ortaya çıkmaya başlar:
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
Böylece s==cn = 4 için.
Genel olarak, bunun gibi binom katsayıları elde ederiz (↓, i, → 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 . . .
. .
. .
. .
Bunu görmek için, bazıları için bunu düşünün ive jvar:
- x = ncr (n, i + 1): (i + 1) maskesinin n dışında kesişimi için C kombinasyonları
- y = ncr (ni-1, ji): yukarıdaki her C kombinasyonu için, (j + 2) maskelerinin C içerenlerden kesişimi için y farklı kombinasyon vardır.
- z = ncr (n, j + 1): (j + 1) maskelerinin n dışında kesişimi için farklı kombinasyonlar
Bu kafa karıştırıcı gelebilir, işte bir örnek için uygulanan tanım. İ = 1, j = 2, n = 4 için, şuna benzer (yukarıdaki referans):
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
Yani burada x = 6 (01, 02, 03, 12, 13, 23), y = 2 (her kombinasyon için üç indeksi olan iki c), z = 4 (c012, c013, c023, c123).
Toplamda, (j + 1) indeksleri olan x*ykatsayılar cvardır ve zfarklı olanlar vardır, bu nedenle her biri x*y/zkatsayı dediğimiz zamanlar meydana gelir k_ij. Basit cebirle anlıyoruz k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1).
Dizin tarafından verilir. k_ij = nCr(j+1,i+1)Tüm tanımları hatırlarsanız, göstermemiz gereken tek şey, her sütunun alternatif toplamının 1 vermesidir.
Alternatif toplam s0 - s1 + s2 - s3 +- ... +- s(n-1), böylece şu şekilde ifade edilebilir:
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
Böylece s=ctüm n = 1,2,3, ...