ルビー、かなり高速ですが、入力に依存します
文字列から整数に切り替えることで、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
1つのマスクの一致数は、二項係数によって容易に計算されます。たとえば、122020
3 2
と1 0
と2 が必要1
です。したがって、nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3
このマスクに一致するさまざまなバイナリ文字列があります。
n個のマスクm_1、m_2、... m_nの共通部分はマスクqであり、バイナリ文字列sはすべてのマスクm_iに一致する場合にのみqに一致します。
2つのマスクm_1とm_2を取る場合、その交差は簡単に計算されます。m_1 [i] == 2の場合は、m_1 [i] = m_2 [i]と設定します。交差点の間122020
と111222
です111020
。
122020 (matched by 3 strings, 111000 110010 101010)
111222 (matched by 1 string, 111000)
111020 (matched by 1 string, 111000)
2つの個別のマスクは3 + 1 = 4文字列で一致し、交差マスクは1つの文字列で一致するため、1つまたは両方のマスクに一致する3 + 1-1 = 3個の一意の文字列があります。
N(m_1、m_2、...)を、すべてのm_iに一致する文字列の数と呼びます。上記と同じロジックを適用して、包含除外の原則によって与えられた、少なくとも1つのマスクと一致する一意の文字列の数を計算できます。以下のように、このように表示されます。
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) -+ ...
たとえば200枚のうち30枚のマスクをとるには、たくさんの組み合わせがあります。
したがって、このソリューションは、定型入力の高次の交差が多く存在しないことを前提としています。n> 2マスクのほとんどのnタプルには、一般的な一致はありません。
ここのコードを使用してください。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つのマスクの場合を考えてみましょう。最初にthen 0
とを呼び出します1
。すべてのバランスのとれたバイナリ文字列を取得し、一致するマスクに従って分類します。c0
マスクのみ一致するものの数であり0
、c1
唯一の一致するもののnunber 1
、c01
それらに一致マスク0
とは1
。
ましょうs0
各マスクの一致の数(これらは重複していてもよい)の数の和です。ましょうs1
マスクの各対の一致の数(2-組み合わせ)の和です。させるs_i
マスクの各(i + 1)の組み合わせに対する一致数の和であること。n-masksの一致数は、すべてのマスクに一致するバイナリ文字列の数です。
n個のマスクがある場合、必要な出力は、すべてc
のの合計です。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の場合。たとえば、n = 2およびn == 3 の場合、(i + 1)インデックスを持つc__i
すべてc
ののを表します。c__1 = c01
c__1 = c01 + c02 + c12
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):nのうち(i + 1)マスクの共通部分の組み合わせC
- y = ncr(ni-1、ji):上記のCの組み合わせごとに、Cを含むマスクのうち(j + 2)マスクの共通部分にyの異なる組み合わせがあります。
- z = ncr(n、j + 1):nのうち(j + 1)マスクの共通部分のさまざまな組み合わせ
混乱するかもしれませんが、ここでは例に適用された定義を示します。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(各組み合わせに対して3つのインデックスを持つ2つのc)、z = 4(c012、c013、c023、c123)です。
合計で、(j + 1)インデックスを持つx*y
係数c
があり、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、...