rubino, abbastanza veloce, ma dipende dall'input
Ora accelera di un fattore 2 ~ 2,5 passando da stringhe a numeri interi.
Uso:
cat <input> | ruby this.script.rb
Per esempio.
mad_gaksha@madlab ~/tmp $ ruby c50138.rb < c50138.inp2
number of matches: 298208861472
took 0.05726237 s
Il numero di corrispondenze per una singola maschera viene facilmente calcolato dal coefficiente binomiale. Quindi ad esempio ha 122020bisogno di 3 2s riempiti, 1 0e 2 1. Quindi ci sono nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3diverse stringhe binarie che corrispondono a questa maschera.
Un'intersezione tra n maschere m_1, m_2, ... m_n è una maschera q, tale che una stringa binaria s corrisponde a q solo se corrisponde a tutte le maschere m_i.
Se prendiamo due maschere m_1 e m_2, la sua intersezione viene facilmente calcolata. Basta impostare m_1 [i] = m_2 [i] se m_1 [i] == 2. L'intersezione tra 122020e 111222è 111020:
122020 (matched by 3 strings, 111000 110010 101010)
111222 (matched by 1 string, 111000)
111020 (matched by 1 string, 111000)
Le due maschere individuali sono abbinate da 3 + 1 = 4 stringhe, la maschera di intersezione è abbinata da una stringa, quindi ci sono 3 + 1-1 = 3 stringhe uniche che corrispondono a una o entrambe le maschere.
Chiamerò N (m_1, m_2, ...) il numero di stringhe corrispondenti a tutti i m_i. Applicando la stessa logica di cui sopra, possiamo calcolare il numero di stringhe univoche associate a almeno una maschera, dato dal principio di esclusione dell'inclusione e vedere anche di seguito, in questo modo:
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) -+ ...
Ci sono molte, molte, molte combinazioni di prendere, diciamo 30 maschere su 200.
Quindi questa soluzione presuppone che non esistano molte intersezioni di ordine elevato delle maschere di input, vale a dire. la maggior parte delle n-tuple di n> 2 maschere non avranno corrispondenze comuni.
Usa qui il codice, il codice su ideone potrebbe non essere aggiornato.
Ho aggiunto una funzione remove_duplicatesche può essere utilizzata per pre-elaborare l'input ed eliminare le maschere in modo m_itale che tutte le stringhe che corrispondono ad essa corrispondano anche a un'altra maschera m_j. , quindi la funzione non è ancora applicata ai dati nel codice seguente.
Codice:
# 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"
Questo si chiama principio di esclusione dell'inclusione, ma prima che qualcuno me lo indicasse avevo la mia prova, quindi eccola. Fare qualcosa da soli è comunque fantastico.
Consideriamo il caso di 2 maschere, chiama quindi 0e 1, prima. Prendiamo ogni stringa binaria bilanciata e la classifichiamo in base alla maschera o alle maschere corrispondenti. c0è il numero di quelli che corrispondono solo alla maschera 0, c1il numero di quelli che corrispondono solo 1, c01quelli che corrispondono alla maschera 0e 1.
Sia s0la somma numerica del numero di corrispondenze per ciascuna maschera (possono sovrapporsi). Sia s1la somma del numero di corrispondenze per ciascuna coppia (2 combinazioni) di maschere. Sia s_ila somma del numero di corrispondenze per ciascuna (i + 1) combinazione di maschere. Il numero di corrispondenze di n-maschere è il numero di stringhe binarie che corrispondono a tutte le maschere.
Se ci sono n maschere, l'output desiderato è la somma di tutti c, cioè. c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1). Ciò che il programma calcola è la somma alternata di tutti s, vale a dire. s = s_0-s_1+s_2-+...+-s_(n-1). Vogliamo dimostrarlo s==c.
n = 1 è ovvio. Considera n = 2. Contando tutte le partite di maschera 0dà c0+c01(il numero di stringhe corrisponde solo a 0 + quelle che corrispondono a entrambe 0e 1), contando tutte le partite di 1dà c1+c02. Possiamo illustrarlo come segue:
0: c0 c01
1: c1 c10
Per definizione, s0 = c0 + c1 + c12. s1è il numero totale di corrispondenze di ciascuna combinazione 2 di [0,1], ad es. tutti uniqye c_ijs. Tienilo a mente c01=c10.
s0 = c0 + c1 + 2 c01
s1 = c01
s = s0 - s1 = c0 + c1 + c01 = c
Quindi s=cper n = 2.
Ora considera 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
Quindi s=cper n = 3. c__irappresenta la di tutte le cs con (i + 1) indici, ad esempio c__1 = c01per n = 2 e c__1 = c01 + c02 + c12per n == 3.
Per n = 4, inizia a emergere un modello:
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
Quindi s==cper n = 4.
In generale, otteniamo coefficienti binomiali come questo (↓ è 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 . . .
. .
. .
. .
Per vedere questo, considera che per alcuni ie jci sono:
- x = ncr (n, i + 1): combinazioni C per l'intersezione della maschera (i + 1) da n
- y = ncr (ni-1, ji): per ogni combinazione C sopra, ci sono y diverse combinazioni per l'intersezione di (j + 2) maschere da quelle che contengono C
- z = ncr (n, j + 1): diverse combinazioni per l'intersezione di (j + 1) maschere da n
Poiché ciò può sembrare confuso, ecco la definizione applicata a un esempio. Per i = 1, j = 2, n = 4, è simile al seguente (vedi sopra):
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
Quindi qui x = 6 (01, 02, 03, 12, 13, 23), y = 2 (due c con tre indici per ogni combinazione), z = 4 (c012, c013, c023, c123).
In totale, ci sono x*ycoefficienti ccon (j + 1) indici, e ce ne sono zdiversi, quindi ognuno si verifica per x*y/ztempi, che chiamiamo coefficiente k_ij. Con una semplice algebra, otteniamo k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1).
Quindi l'indice è dato da k_ij = nCr(j+1,i+1)Se ricordi tutte le definizioni, tutto ciò che dobbiamo mostrare è che la somma alternata di ogni colonna dà 1.
La somma alternata s0 - s1 + s2 - s3 +- ... +- s(n-1)può quindi essere espressa come:
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
Quindi s=cper tutti n = 1,2,3, ...