rubis, assez rapide, mais cela dépend de l'entrée
Accélérez maintenant d'un facteur 2 ~ 2,5 en passant des chaînes aux entiers.
Usage:
cat <input> | ruby this.script.rb
Par exemple.
mad_gaksha@madlab ~/tmp $ ruby c50138.rb < c50138.inp2
number of matches: 298208861472
took 0.05726237 s
Le nombre de correspondances pour un seul masque est facilement calculé par le coefficient binomial. Ainsi, par exemple, il 122020
faut 3 2
s remplis, 1 0
et 2 1
. Il existe donc nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3
différentes chaînes binaires correspondant à ce masque.
Une intersection entre n masques m_1, m_2, ... m_n est un masque q, de sorte qu'une chaîne binaire s ne correspond à q que si elle correspond à tous les masques m_i.
Si nous prenons deux masques m_1 et m_2, son intersection est facilement calculée. Définissez simplement m_1 [i] = m_2 [i] si m_1 [i] == 2. L'intersection entre 122020
et 111222
est 111020
:
122020 (matched by 3 strings, 111000 110010 101010)
111222 (matched by 1 string, 111000)
111020 (matched by 1 string, 111000)
Les deux masques individuels sont appariés par 3 + 1 = 4 chaînes, le masque d'intersection est apparié par une chaîne, il y a donc 3 + 1-1 = 3 chaînes uniques correspondant à l'un ou aux deux masques.
J'appellerai N (m_1, m_2, ...) le nombre de chaînes correspondant à tous les m_i. En appliquant la même logique que ci-dessus, nous pouvons calculer le nombre de chaînes uniques correspondant à au moins un masque, donné par le principe d'exclusion d'inclusion et voir également ci-dessous, comme ceci:
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) -+ ...
Il existe de très nombreuses combinaisons de prises, disons 30 masques sur 200.
Donc, cette solution fait l'hypothèse qu'il n'y a pas beaucoup d'intersections d'ordre élevé des masques d'entrée, c'est-à-dire. la plupart des n-tuples de n> 2 masques n'auront aucune correspondance commune.
Utilisez le code ici, le code à ideone peut être obsolète.
J'ai ajouté une fonction remove_duplicates
qui peut être utilisée pour prétraiter l'entrée et supprimer les masques de m_i
sorte que toutes les chaînes qui y correspondent correspondent également à un autre masque m_j
., Pour l'entrée actuelle, cela prend en fait plus de temps car il n'y a pas de tels masques (ou pas beaucoup) , la fonction n'est donc pas encore appliquée aux données dans le code ci-dessous.
Code:
# 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"
C'est ce qu'on appelle le principe d'exclusion de l'inclusion, mais avant que quelqu'un ne me le montre, j'avais ma propre preuve, alors voilà. Cependant, faire quelque chose vous fait du bien.
Considérons le cas de 2 masques, appelons ensuite 0
et 1
, d'abord. Nous prenons chaque chaîne binaire équilibrée et la classons en fonction du ou des masques auxquels elle correspond. c0
est le nombre de ceux qui correspondent uniquement au masque 0
, c1
le nombre de ceux qui correspondent uniquement 1
, c01
ceux qui correspondent au masque 0
et 1
.
Soit s0
la somme numérique du nombre de correspondances pour chaque masque (elles peuvent se chevaucher). Soit s1
la somme du nombre de correspondances pour chaque paire (2 combinaisons) de masques. Soit s_i
la somme du nombre de correspondances pour chaque (i + 1) combinaison de masques. Le nombre de correspondances de n-masques est le nombre de chaînes binaires correspondant à tous les masques.
S'il y a n masques, la sortie souhaitée est la somme de tous c
, c'est-à-dire. c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1)
. Ce que le programme calcule est la somme alternée de tous s
, c'est-à-dire. s = s_0-s_1+s_2-+...+-s_(n-1)
. Nous voulons le prouver s==c
.
n = 1 est évident. Considérons n = 2. Compter toutes les correspondances de mask 0
donne c0+c01
(le nombre de chaînes ne correspondant qu'à 0 + celles correspondant à la fois à 0
et 1
), compter toutes les correspondances de 1
donne c1+c02
. Nous pouvons illustrer cela comme suit:
0: c0 c01
1: c1 c10
Par définition, s0 = c0 + c1 + c12
. s1
est le nombre total de correspondances de chaque combinaison de 2 [0,1]
, c'est-à-dire. tous uniqye c_ij
s. Gardez cela à l'esprit c01=c10
.
s0 = c0 + c1 + 2 c01
s1 = c01
s = s0 - s1 = c0 + c1 + c01 = c
Ainsi s=c
pour n = 2.
Considérons maintenant 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
Ainsi s=c
pour n = 3. c__i
représente le de tous les c
s avec (i + 1) indices, par exemple c__1 = c01
pour n = 2 et c__1 = c01 + c02 + c12
pour n == 3.
Pour n = 4, un modèle commence à émerger:
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
Ainsi s==c
pour n = 4.
En général, nous obtenons des coefficients binomiaux comme celui-ci (↓ est i, → est 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 . . .
. .
. .
. .
Pour voir cela, considérez cela pour certains i
et j
, il y a:
- x = ncr (n, i + 1): combinaisons C pour l'intersection de (i + 1) masque sur n
- y = ncr (ni-1, ji): pour chaque combinaison C ci-dessus, il existe y différentes combinaisons pour l'intersection de (j + 2) masques parmi ceux contenant C
- z = ncr (n, j + 1): différentes combinaisons pour l'intersection de (j + 1) masques sur n
Comme cela peut sembler déroutant, voici la définition appliquée à un exemple. Pour i = 1, j = 2, n = 4, cela ressemble à ceci (cf. ci-dessus):
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
Donc ici x = 6 (01, 02, 03, 12, 13, 23), y = 2 (deux c avec trois indices pour chaque combinaison), z = 4 (c012, c013, c023, c123).
Au total, il y a des x*y
coefficients c
avec des indices (j + 1), et il y en a z
différents, donc chacun se produit x*y/z
fois, que nous appelons le coefficient k_ij
. Par simple algèbre, on obtient k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1)
.
Donc, l'indice est donné par k_ij = nCr(j+1,i+1)
Si vous vous souvenez de toutes les définitions, tout ce que nous devons montrer est que la somme alternée de chaque colonne donne 1.
La somme alternée s0 - s1 + s2 - s3 +- ... +- s(n-1)
peut ainsi s'exprimer comme:
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
Ainsi s=c
pour tout n = 1,2,3, ...