rubinowy, dość szybki, ale zależy to od danych wejściowych
Teraz przyspieszenie o współczynnik 2 ~ 2,5 poprzez zmianę ciągów znaków na liczby całkowite.
Stosowanie:
cat <input> | ruby this.script.rb
Na przykład.
mad_gaksha@madlab ~/tmp $ ruby c50138.rb < c50138.inp2
number of matches: 298208861472
took 0.05726237 s
Liczba dopasowań dla pojedynczej maski jest łatwo obliczana przez współczynnik dwumianowy. Na przykład 122020wymaga 3 2s wypełnienia, 1 0i 2 1. Zatem istnieją nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3różne ciągi binarne pasujące do tej maski.
Przecięcie n maski m_1, m_2, ... m_n jest maską q, tak że ciąg binarny s pasuje do q tylko iff pasuje do wszystkich m_i.
Jeśli weźmiemy dwie maski m_1 i m_2, jego przecięcie można łatwo obliczyć. Wystarczy ustawić m_1 [i] = m_2 [i], jeśli m_1 [i] == 2. Przecięcie między 122020i 111222jest 111020:
122020 (matched by 3 strings, 111000 110010 101010)
111222 (matched by 1 string, 111000)
111020 (matched by 1 string, 111000)
Dwie indywidualne maski są dopasowane przez 3 + 1 = 4 ciągi, maska przecięcia jest dopasowana przez jeden ciąg, więc istnieją 3 + 1-1 = 3 unikalne ciągi pasujące do jednej lub obu masek.
Wywołam N (m_1, m_2, ...) liczbę ciągów pasujących do wszystkich m_i. Stosując tę samą logikę jak powyżej, możemy obliczyć liczbę unikatowych ciągów dopasowanych przez co najmniej jedną maskę, podaną przez zasadę wykluczania włączenia, i patrz również poniżej:
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) -+ ...
Istnieje wiele, wiele kombinacji kombinacji, powiedzmy 30 masek na 200.
To rozwiązanie zakłada więc, że nie ma wielu przecięć wyższych rzędów masek wejściowych, tj. większość n-krotek n> 2 masek nie będzie mieć wspólnych dopasowań.
Użyj kodu tutaj, kod w ideone może być przestarzały.
Dodałem funkcję, remove_duplicatesktórej można użyć do wstępnego przetworzenia danych wejściowych i usuwania masek, m_itak aby wszystkie pasujące do nich ciągi pasowały również do innej maski m_j., W przypadku bieżącego wprowadzania danych trwa to dłużej, ponieważ nie ma takich masek (lub ich niewiele) , więc funkcja nie jest jeszcze stosowana do danych w poniższym kodzie.
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"
Nazywa się to zasadą wykluczenia włączenia, ale zanim ktoś mi to wskazał, miałem swój własny dowód, więc proszę bardzo. Robienie czegoś samemu sprawia jednak przyjemność.
Rozważmy przypadek 2 masek, zadzwoń wtedy 0i 1najpierw. Bierzemy każdy zbalansowany ciąg binarny i klasyfikujemy go według pasujących masek. c0to liczba pasujących tylko do maski 0, c1liczba pasujących tylko pasujących 1, c01pasujących do maski 0i 1.
Niech s0będzie sumą liczbową liczby dopasowań dla każdej maski (mogą się nakładać). Niech s1będzie sumą liczby dopasowań dla każdej pary (2 kombinacji) masek. Niech s_ibędzie sumą liczby dopasowań dla każdej (i + 1) kombinacji masek. Liczba dopasowań n-masek to liczba ciągów binarnych pasujących do wszystkich masek.
Jeśli jest n masek, pożądanym wynikiem jest suma wszystkich c, tj. c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1). Program oblicza na przemian sumę wszystkich s, tzn. s = s_0-s_1+s_2-+...+-s_(n-1). Chcemy to udowodnić s==c.
n = 1 jest oczywiste. Zastanów się n = 2. Zliczanie wszystkich dopasowań maski 0daje c0+c01(liczba ciągów pasujących tylko do 0 + pasujących do obu 0i 1), liczenie wszystkich dopasowań 1daje c1+c02. Możemy to zilustrować w następujący sposób:
0: c0 c01
1: c1 c10
Z definicji s0 = c0 + c1 + c12. s1to łączna liczba dopasowań każdej 2 kombinacji [0,1], tj. wszystkie uniqye c_ijs. Pamiętaj o tym c01=c10.
s0 = c0 + c1 + 2 c01
s1 = c01
s = s0 - s1 = c0 + c1 + c01 = c
Zatem s=cdla n = 2.
Teraz rozważ 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
Zatem s=cdla n = 3. c__ireprezentuje wszystkie cs ze wskaźnikami (i + 1), np. c__1 = c01dla n = 2 i c__1 = c01 + c02 + c12dla n == 3.
Dla n = 4 zaczyna się pojawiać wzór:
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
Zatem s==cdla n = 4.
Ogólnie rzecz biorąc, otrzymujemy współczynniki dwumianowe takie jak to (↓ to i, → to 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 . . .
. .
. .
. .
Aby to zobaczyć, uważają, że dla niektórych ii jistnieją:
- x = ncr (n, i + 1): kombinacje C dla przecięcia (i + 1) maski z n
- y = ncr (ni-1, ji): dla każdej kombinacji C powyżej istnieją y różne kombinacje przecięcia masek (j + 2) spośród tych zawierających C
- z = ncr (n, j + 1): różne kombinacje przecięcia masek (j + 1) z n
Może się to wydawać mylące, oto definicja zastosowana do przykładu. Dla i = 1, j = 2, n = 4 wygląda to tak (patrz wyżej):
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
Więc tutaj x = 6 (01, 02, 03, 12, 13, 23), y = 2 (dwa c z trzema indeksami dla każdej kombinacji), z = 4 (c012, c013, c023, c123).
W sumie istnieją x*ywspółczynniki co indeksach (j + 1) i są one zróżne, więc każdy zachodzi x*y/zrazy, które nazywamy współczynnikiem k_ij. Prostą algebrą otrzymujemy k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1).
Tak więc indeks podaje: k_ij = nCr(j+1,i+1)Jeśli przypomnisz sobie wszystkie definicje, wszystko, co musimy wykazać, to że naprzemienna suma każdej kolumny daje 1.
Suma naprzemienna s0 - s1 + s2 - s3 +- ... +- s(n-1)może zatem być wyrażona jako:
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
Zatem s=cdla wszystkich n = 1,2,3 ...