Skip to content

Instantly share code, notes, and snippets.

@snuke
Last active July 15, 2017 06:03
Show Gist options
  • Select an option

  • Save snuke/797cfdc55fe79c799c93fc4b7464c675 to your computer and use it in GitHub Desktop.

Select an option

Save snuke/797cfdc55fe79c799c93fc4b7464c675 to your computer and use it in GitHub Desktop.
ICPC2017国内予選E

最短が最長な関数一覧

最短の最長は35。

ORも使っていいなら31。

フォーマット

関数 最短長 式の種類数(左右を入れ替えただけのものは同一とみなす)
式の例

アルゴリズム

関数の個数(=2^(2^変数の個数))をNとして、式はO(N^2)の適当な探索で復元した。

各関数における最短を求めるだけなら、式の長さの上限をLとして、O(L^2 N log N)で求められる。(変数が5個でも数日で実行が終わる!すごい!)

dp[0~N-1]を埋めることが目標。

0,1,a,b,c,dにあたる場所を1で埋めておく。
for l = 1~L:
  s[] = dp[i]がlである場所に1、そうでない場所に0を書いた長さNの配列
  NOTの更新(a[i]==1ならdp[i^(N-1)]にl+1でminをとる)
  for r = 1~l:
    t[] = dp[i]がrである場所に1、そうでない場所に0を書いた長さNの配列
    ANDの更新(後述)
    XORの更新(後述)

Lが分かっていない場合は更新がなくなるまで繰り返すとよい。


MをN=2^Mとなるような数(要は桁数)として、ANDの更新は以下の通り。

高速ゼータ変換をして掛けて高速メビウス変換です。

for i = 0~M-1:
  for j = 0~N-1:
    if (j>>i&1) == 0:
      s[j] += s[j|1<<i]
      t[j] += t[j|1<<i]
d = 長さNの配列
for i = 0~N-1:
  d[i] = s[i]*t[i]
for i = 0~M-1:
  for j = 0~N-1:
    if (j>>i&1) == 0:
      d[j] -= d[j|1<<i]
for i = 0~N-1:
  if d[i] > 0:
    dp[i] = min(dp[i], l+r+3)

次にXOR。(ANDでs,tに破壊的な操作をしましたが元に戻してからやります)

高速アダマール変換をして掛けて逆変換です。さっきと変換方法が変わっただけ。

アダマール変換はM次元でmod2な(離散)FFTです。

ada()はアダマール変換、dad()はその逆変換だと思って読んで下さい(それぞれのコードは別ファイルとしてつけています)

ada(s)
ada(t)
d = 長さNの配列
for i = 0~N-1:
  d[i] = s[i]*t[i]
dad(d)
for i = 0~N-1:
  if d[i] > 0:
    dp[i] = min(dp[i], l+r+3)
// 高速アダマール変換
typedef long long Int;
void ada(vector<Int>& d) {
int n = d.size();
for (int i = n; i >= 1; i >>= 1) {
for (int j = 0; j < n; ++j) if (j&i) {
int x = d[j^i], y = d[j];
d[j^i] = x+y;
d[j] = x-y;
}
}
}
void dad(vector<Int>& d) {
int n = d.size();
for (int i = 1; i <= n; i <<= 1) {
for (int j = 0; j < n; ++j) if (j&i) {
Int x = d[j^i], y = d[j];
d[j^i] = (x+y)/2;
d[j] = (x-y)/2;
}
}
}
0001011111101001 35 6229476
((((-(-a*-d)*-c)^-b)*(-b^a))^(d^c))
0001100011101001 35 418
((-(-(-a*-b)*-c)*-d)^((c^a)*(c^b)))
0001111001111001 35 6229476
((((-(-a*-c)*-d)^-b)*(-b^a))^(d^c))
0001111010001001 35 418
((-(-(-a*-b)*-d)*-c)^((d^a)*(d^b)))
0010010011101001 35 418
((-(-(-a*-c)*-b)*-d)^((b^a)*(c^b)))
0010111001001001 35 418
((-(-(-a*-d)*-b)*-c)^((b^a)*(d^b)))
0011011001101101 35 6229476
((((-(-a*-b)*-d)^-c)*(-c^a))^(d^b))
0011011010100001 35 418
((-(-(-a*-c)*-d)*-b)^((d^a)*(d^c)))
0011101001100001 35 418
((-(-(-a*-d)*-c)*-b)^((c^a)*(d^c)))
0100001011101001 35 418
((-(-(-b*-c)*-a)*-d)^((b^a)*(c^a)))
0100111000101001 35 418
((-(-(-b*-d)*-a)*-c)^((b^a)*(d^a)))
0101011001101011 35 6229476
((((-(-a*-b)*-d)^-c)*(-c^b))^(d^a))
0101011011000001 35 418
((-(-(-b*-c)*-d)*-a)^((d^b)*(d^c)))
0101110001100001 35 418
((-(-(-b*-d)*-c)*-a)^((c^b)*(d^c)))
0111001000101001 35 418
((-(-(-c*-d)*-a)*-b)^((c^a)*(d^a)))
0111010001001001 35 418
((-(-(-c*-d)*-b)*-a)^((c^b)*(d^b)))
1000000111101001 35 15663
(-(-(-d*b)*(c^a))*-(-(-d*c)*(b^a)))
1000111000011001 35 15663
(-(-(-c*b)*(d^a))*-(-(-c*d)*(b^a)))
1001101011000001 35 648
((-(-(-b*-c)*-a)*-d)^(((d^b)*c)^a))
1001110010100001 35 648
((-(-(-a*-c)*-b)*-d)^(((d^a)*c)^b))
1010011011000001 35 648
((-(-(-b*-c)*-a)*-d)^(((d^c)*b)^a))
1010110001100001 35 648
((-(-(-a*-c)*-b)*-d)^(((b^a)*c)^b))
1011001000100101 35 15663
(-(-(-b*c)*(d^a))*-(-(-b*d)*(c^a)))
1011010010001001 35 648
((-(-(-a*-b)*-c)*-d)^(((d^a)*b)^c))
1011100001001001 35 648
((-(-(-a*-b)*-c)*-d)^(((c^a)*b)^c))
1100011010100001 35 648
((-(-(-a*-c)*-b)*-d)^(((d^c)*a)^b))
1100101001100001 35 648
((-(-(-b*-c)*-a)*-d)^(((b^a)*c)^a))
1101001010001001 35 648
((-(-(-a*-b)*-c)*-d)^(((d^b)*a)^c))
1101010001000011 35 15663
(-(-(-a*c)*(d^b))*-(-(-a*d)*(c^b)))
1101100000101001 35 648
((-(-(-a*-b)*-c)*-d)^(((c^b)*a)^c))
1110001001001001 35 648
((-(-(-b*-c)*-a)*-d)^(((c^a)*b)^a))
1110010000101001 35 648
((-(-(-a*-c)*-b)*-d)^(((c^b)*a)^b))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment