rubí, bastante rápido, pero depende de la entrada
Ahora acelere por un factor de 2 ~ 2.5 cambiando de cadenas a enteros.
Uso:
cat <input> | ruby this.script.rb
P.ej.
mad_gaksha@madlab ~/tmp $ ruby c50138.rb < c50138.inp2
number of matches: 298208861472
took 0.05726237 s
El número de coincidencias para una sola máscara se calcula fácilmente por el coeficiente binomial. Entonces, por ejemplo, 122020
necesita 3 2
s llenos, 1 0
y 2 1
. Por lo tanto, hay nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3
diferentes cadenas binarias que coinciden con esta máscara.
Una intersección entre n máscaras m_1, m_2, ... m_n es una máscara q, de modo que una cadena binaria s coincide con q solo si coincide con todas las máscaras m_i.
Si tomamos dos máscaras m_1 y m_2, su intersección se calcula fácilmente. Simplemente configure m_1 [i] = m_2 [i] si m_1 [i] == 2. La intersección entre 122020
y 111222
es 111020
:
122020 (matched by 3 strings, 111000 110010 101010)
111222 (matched by 1 string, 111000)
111020 (matched by 1 string, 111000)
Las dos máscaras individuales se combinan con 3 + 1 = 4 cadenas, la máscara de intersección se corresponde con una cadena, por lo tanto, hay 3 + 1-1 = 3 cadenas únicas que coinciden con una o ambas máscaras.
Llamaré a N (m_1, m_2, ...) el número de cadenas que coinciden con todos m_i. Aplicando la misma lógica que la anterior, podemos calcular el número de cadenas únicas que coinciden con al menos una máscara, dada por el principio de exclusión de inclusión y ver a continuación también, así:
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) -+ ...
Hay muchas, muchas, muchas combinaciones de tomar, digamos 30 máscaras de 200.
Por lo tanto, esta solución supone que no existen muchas intersecciones de orden superior de las máscaras de entrada, es decir. La mayoría de las n-tuplas de n> 2 máscaras no tendrán coincidencias comunes.
Use el código aquí, el código de ideone puede estar desactualizado.
Agregué una función remove_duplicates
que se puede usar para preprocesar la entrada y eliminar máscaras de m_i
modo que todas las cadenas que coincidan también coincidan con otra máscara m_j
., Para la entrada actual, esto realmente lleva más tiempo ya que no hay tales máscaras (o no hay muchas) , por lo que la función aún no se aplica a los datos en el código a continuación.
Código:
# 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"
Esto se llama el principio de exclusión de inclusión, pero antes de que alguien me lo señalara tenía mi propia prueba, así que aquí va. Sin embargo, hacer algo por ti mismo se siente genial.
Consideremos el caso de 2 máscaras, llame entonces 0
y 1
, primero. Tomamos todas las cadenas binarias balanceadas y las clasificamos de acuerdo con qué máscara (s) coinciden. c0
es el número de aquellos que solo coinciden con la máscara 0
, c1
el número de aquellos que solo coinciden 1
, c01
los que coinciden con la máscara 0
y 1
.
Sea s0
la suma numérica del número de coincidencias para cada máscara (pueden superponerse). Sea s1
la suma de la cantidad de coincidencias para cada par (2 combinaciones) de máscaras. Sea s_i
la suma del número de coincidencias para cada combinación de máscaras (i + 1). El número de coincidencias de n-máscaras es el número de cadenas binarias que coinciden con todas las máscaras.
Si hay n máscaras, la salida deseada es la suma de todas c
, es decir. c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1)
. Lo que calcula el programa es la suma alterna de todos s
, es decir. s = s_0-s_1+s_2-+...+-s_(n-1)
. Queremos probar eso s==c
.
n = 1 es obvio. Considere n = 2. Contando todos los partidos de la máscara 0
da c0+c01
(el número de cadenas que coinciden sólo 0 + coincidente tanto los 0
e 1
), contando todos los partidos del 1
da c1+c02
. Podemos ilustrar esto de la siguiente manera:
0: c0 c01
1: c1 c10
Por definición, s0 = c0 + c1 + c12
. s1
es el número total de coincidencias de cada combinación de 2 [0,1]
, es decir. todos uniqye c_ij
s. Ten en cuenta eso c01=c10
.
s0 = c0 + c1 + 2 c01
s1 = c01
s = s0 - s1 = c0 + c1 + c01 = c
Así s=c
para n = 2.
Ahora considere 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
Así s=c
para n = 3. c__i
representa el de todos los c
s con (i + 1) índices, por ejemplo, c__1 = c01
para n = 2 y c__1 = c01 + c02 + c12
para n == 3.
Para n = 4, un patrón comienza a emerger:
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
Así s==c
para n = 4.
En general, obtenemos coeficientes binomiales como este (↓ es i, → es 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 . . .
. .
. .
. .
Para ver esto, considere eso para algunos i
y j
, hay:
- x = ncr (n, i + 1): combinaciones C para la intersección de la máscara (i + 1) de n
- y = ncr (ni-1, ji): para cada combinación C anterior, existen y diferentes combinaciones para la intersección de (j + 2) máscaras de las que contienen C
- z = ncr (n, j + 1): diferentes combinaciones para la intersección de (j + 1) máscaras de n
Como eso puede sonar confuso, aquí está la definición aplicada a un ejemplo. Para i = 1, j = 2, n = 4, se ve así (cf. arriba):
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
Entonces, aquí x = 6 (01, 02, 03, 12, 13, 23), y = 2 (dos c con tres índices para cada combinación), z = 4 (c012, c013, c023, c123).
En total, hay x*y
coeficientes c
con índices (j + 1), y hay z
diferentes, por lo que cada uno ocurre x*y/z
veces, lo que llamamos coeficiente k_ij
. Por álgebra simple, obtenemos k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1)
.
Entonces, el índice está dado por k_ij = nCr(j+1,i+1)
Si recuerda todas las definiciones, todo lo que necesitamos mostrar es que la suma alterna de cada columna da 1.
La suma alterna s0 - s1 + s2 - s3 +- ... +- s(n-1)
se puede expresar como:
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
Así, s=c
para todos n = 1,2,3, ...