рубін, досить швидкий, але це залежить від введення
Тепер пришвидшити на коефіцієнт 2 ~ 2,5 шляхом переходу від рядків до цілих чисел.
Використання:
cat <input> | ruby this.script.rb
Напр.
mad_gaksha@madlab ~/tmp $ ruby c50138.rb < c50138.inp2
number of matches: 298208861472
took 0.05726237 s
Кількість збігів для однієї маски легко обчислюється двочленним коефіцієнтом. Так, наприклад, 122020
потрібно 2
заповнити 3 с, 1 0
і 2 1
. Таким чином, існують nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3
різні бінарні рядки, що відповідають цій масці.
Перетин між n масками m_1, m_2, ... m_n - це маска q, така що двійковий рядок s відповідає q лише якщо вона відповідає всім маскам m_i.
Якщо взяти дві маски m_1 і m_2, її перетин легко обчислити. Просто встановіть m_1 [i] = m_2 [i], якщо m_1 [i] == 2. Перетин між 122020
і 111222
є 111020
:
122020 (matched by 3 strings, 111000 110010 101010)
111222 (matched by 1 string, 111000)
111020 (matched by 1 string, 111000)
Дві окремі маски поєднуються 3 + 1 = 4 рядки, міжсекційна маска зіставлена однією струною, таким чином, є 3 + 1-1 = 3 унікальних рядка, що відповідають одній або обом маскам.
Я зателефоную N (m_1, m_2, ...) кількість рядків, які відповідають всім m_i. Застосовуючи ту ж логіку, що і вище, ми можемо обчислити кількість унікальних рядків, зіставлених принаймні однією маскою, заданими принципом виключення включення, а також див. Нижче, як це:
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) -+ ...
Є багато, багато, багато комбінацій прийому, скажімо, 30 масок з 200.
Отже, це рішення робить припущення, що існує не так багато перехресть високого порядку вхідних масок, тобто. більшість n-кортежів n> 2 масок не матимуть спільних збігів.
Використовуйте код тут, код у ideone може бути застарілим.
Я додав функцію, remove_duplicates
яку можна використовувати для попередньої обробки введення та видалення масок m_i
таким чином, що всі рядки, які відповідають їй, також відповідають іншій масці m_j
., Для поточного введення це фактично займає більше часу, оскільки таких масок немає (або їх не багато) , тому функція не застосовується до даних ще в наведеному нижче коді.
Код:
# 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"
Це називається принципом виключення включення, але перед тим, як хтось на мене вказав на це, у мене було власне доведення, так ось що. Хоча щось робити, то чудово себе почуваєш.
Розглянемо випадок 2 масок, зателефонуйте потім 0
і 1
, спочатку. Ми беремо кожну збалансовану двійкову рядок і класифікуємо її відповідно до того, яка маска (и) вона відповідає. c0
Число тих , які відповідають лише маскують 0
, c1
Nunber з тих , які відповідають тільки 1
, c01
ті , що маски матч 0
і 1
.
Дозвольте s0
бути числовою кількістю кількості збігів для кожної маски (вони можуть перекриватися). Нехай s1
буде сума кількості відповідностей для кожної пари (2-комбінація) масок. Нехай s_i
буде сума кількості збігів для кожної (i + 1) комбінації масок. Кількість збігів n-масок - це кількість двійкових рядків, що відповідають усім маскам.
Якщо є n масок, бажаний вихід - це сума всіх c
s, тобто. c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1)
. Програма, яка обчислює, - це чергування суми всіх s
, тобто. s = s_0-s_1+s_2-+...+-s_(n-1)
. Ми хочемо довести це s==c
.
n = 1 очевидно. Розглянемо n = 2. Підрахунок всіх матчів маски 0
дає c0+c01
(кількість рядків , відповідне тільки 0 + ті відповідності , як 0
і 1
), вважаючи всі матчі 1
дає c1+c02
. Ми можемо проілюструвати це так:
0: c0 c01
1: c1 c10
За визначенням s0 = c0 + c1 + c12
. s1
- це сума кількість збігів кожної 2-комбінації [0,1]
, тобто. всі uniqye c_ij
s. Майте на увазі це c01=c10
.
s0 = c0 + c1 + 2 c01
s1 = c01
s = s0 - s1 = c0 + c1 + c01 = c
Таким чином s=c
при n = 2.
Тепер розглянемо 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
Таким чином s=c
при n = 3. c__i
являє собою всі c
s з (i + 1) індексами, наприклад, c__1 = c01
для n = 2 та c__1 = c01 + c02 + c12
n == 3.
При n = 4 починає формуватися закономірність:
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
Таким чином s==c
при n = 4.
Взагалі ми отримуємо біноміальні коефіцієнти на зразок цього (↓ є 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 . . .
. .
. .
. .
Щоб побачити це, врахуйте, що для деяких i
і j
є:
- x = ncr (n, i + 1): комбінації C для перетину (i + 1) маски поза n
- y = ncr (ni-1, ji): для кожної комбінації C вище є y різні комбінації для перетину (j + 2) масок із тих, що містять C
- z = ncr (n, j + 1): різні комбінації для перетину (j + 1) масок з n
Оскільки це може здатися заплутаним, ось визначення, застосоване до прикладу. Для i = 1, j = 2, n = 4, це виглядає приблизно так (див. Вище):
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
Отже, тут x = 6 (01, 02, 03, 12, 13, 23), y = 2 (два c з трьома показниками для кожної комбінації), z = 4 (c012, c013, c023, c123).
Загалом є x*y
коефіцієнти c
з (j + 1) індексами, і є z
різні, тому кожен виникає x*y/z
разів, які ми називаємо коефіцієнтом k_ij
. За допомогою простої алгебри ми отримуємо k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1)
.
Отже, індекс задається: k_ij = nCr(j+1,i+1)
Якщо ви пригадуєте всі визначення, все, що нам потрібно показати, - це те, що чергування кожної колонки дає 1.
Таким чином, чергується сума s0 - s1 + s2 - s3 +- ... +- s(n-1)
може бути виражена як:
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
Таким чином s=c
для всіх n = 1,2,3, ...