東京大学 情報理工学研究科 数理情報学 2022年8月実施 第5問
Author
hari64boli64, 祭音Myyura
Description
自然数(正の整数) に対して、
を満たす整数の列 を の三値表現と呼ぶ。 また、 の三値表現 で、 の範囲の各整数 に対して、
が成立するものを の疎な三値表現と呼ぶ。以下の設問に答えよ。
(1) 自然数 に対し、疎な三値表現 で表現可能な自然数の最大値 を求めよ。
(2) 任意の自然数 に対し、 の疎な三値表現は一意的に定まることを示せ。
(3) 自然数 の二進表現を疎な三値表現へ変換する 時間アルゴリズムを設計せよ。
(4) 整数の列 に対して、零でない整数 の個数を と表す。自然数 の疎な三値表現 と任意の三値表現 に対し、
が成り立つことを示せ。
(5) 自然数 に対し、 を集合 上の離散一様分布に従う確率変数とする。 の疎な三値表現 を用いて、確率変数 で定める。 このとき、
が成り立つことを示せ。ただし、 は自然数全体の集合、 は の期待値とする。
题目描述
对自然数(正整数),将满足
的整数序列 称为 的三值表示。 若 的三值表示还满足:对每个整数 ,
则称其为 的稀疏三值表示。回答下列问题。
(1) 对自然数 ,求能够用稀疏三值表示 表示的自然数的最大值 。
(2) 证明任意自然数 的稀疏三值表示都唯一确定。
(3) 设计一个时间复杂度为 的算法,将自然数 的二进制 表示转换为稀疏三值表示。
(4) 对整数序列 ,以 表示其中非零整数 的个数。设 是自然数 的稀疏三值表示, 是 的任意三值表示。证明
(5) 对自然数 ,令 是集合
上的离散均匀随机变量。利用 的稀疏三值表示 ,定义
证明
其中 表示自然数集, 表示 的期望。
Kai
この疎な三値表現は、符号付き二進数の非隣接形式(NAF)である。
(1)
貪欲に 1 を割り当てていくのが最善。 が答え。
(2)
存在性は (3) より言えるので、一意性のみ言えばよい。 相異なる疎な表現 と が存在したとする。 長さが異なる場合は上位に を補う。これらの内、相異なる添え字 の内、最小のものを考える。
の内、片方が の場合、この桁において のズレが生じるが、これ以降の桁において生成できるズレは、 の倍数のみ。 よって、 と で表す数が異なり矛盾。
が、共に か の場合、この桁において のズレが生じるが、これ以降の桁において生成できるズレは、疎性に注意すると、 の倍数のみ。 よって、 と で表す数が異なり矛盾。
以上より、示された。
(3)
下位のビットから見ていって、二進数の を に変換していくのが主な方針である。 詳細は以下。計算量は自明に である。
油断した実装だと、十進法における (二進表現で ) が三値表現で になって、疎でなくなるので注意(一敗)。 正しくは、 である。 実装の入力文字列と出力列は、いずれも下位桁から上位桁の順である。
なお、Slack 上では、上位のビットから貪欲に見ていくという方針もあった。 コード 1 において、anotherSolution という関数で実装している。 尤も、二進表現を疎な三値表現に変換せよという問題だったので、あまり想定解ではないかも知れない。
コード 1
from collections import defaultdict
def toSparseTernaryRepresentation(S: str):
bits = [int(c) for c in S]
ret = []
i = 0
carry = 0
while i < len(bits) or carry:
b = (bits[i] if i < len(bits) else 0) + carry
next_bit = bits[i + 1] if i + 1 < len(bits) else 0
if b % 2 == 0:
ret.append(0)
carry = b // 2
else:
digit = -1 if next_bit == 1 else 1
ret.append(digit)
carry = (b - digit) // 2
i += 1
return ",".join(map(str, ret))
def anotherSolution(n: int):
# ここで L(i) は第 0,...,i-1 桁だけで作れる絶対値の最大値であり、
# 問 (1) の L_{i-1} に対応する。
def L(i):
if i <= 0:
return 0
if i % 2 == 1:
return (2 ** (i + 1) - 1) // 3
else:
return 2 * (2**i - 1) // 3
d = []
for i in range(n.bit_length() + 2)[::-1]:
if abs(n - (2**i)) <= L(i - 1):
n -= 2**i
d.append(1)
elif abs(n + (2**i)) <= L(i - 1):
n += 2**i
d.append(-1)
else:
d.append(0)
d = d[::-1]
while d[-1] == 0:
d.pop()
return ",".join(map(str, d))
def problem5():
maxN = 16
zeroCnt = 0
cntPer3 = defaultdict(int)
for n in range(1, (1 << maxN) + 1):
S = bin(n)[2:][::-1]
T = toSparseTernaryRepresentation(S)
S += "0" * (maxN - len(S))
listT = list(map(int, T.split(",")))
listT += [0] * (maxN - len(listT))
if listT[maxN // 2] == 0:
zeroCnt += 1
cntPer3[tuple(S[maxN // 2 - 1 : maxN // 2 + 2][::-1])] += 1
print(f"result: {zeroCnt/(1<<maxN)}")
print(f"cntPer3: {sorted(cntPer3.items())}")
def main():
maxIntPerDigit = defaultdict(int)
for n in range(1, 1000 + 1):
S = bin(n)[2:][::-1]
# ternary representation
T = toSparseTernaryRepresentation(S)
print(f"binary: {S} | ternary: {T}")
# another solution
T2 = anotherSolution(n)
assert T == T2, f"{T} != {T2}"
# assertion
TasInt = sum([c * (2**i) for i, c in enumerate(list(map(int, T.split(","))))])
assert TasInt == n
# count
maxIntPerDigit[len(T.split(","))] = max(maxIntPerDigit[len(T.split(","))], n)
print(f"maxIntPerDigit: {maxIntPerDigit}")
if __name__ == "__main__":
main()
# problem5()
result
binary: 1 | ternary: 1
binary: 01 | ternary: 0,1
binary: 11 | ternary: -1,0,1
binary: 001 | ternary: 0,0,1
binary: 101 | ternary: 1,0,1
binary: 011 | ternary: 0,-1,0,1
binary: 111 | ternary: -1,0,0,1
binary: 0001 | ternary: 0,0,0,1
binary: 1001 | ternary: 1,0,0,1
binary: 0101 | ternary: 0,1,0,1
binary: 1101 | ternary: -1,0,-1,0,1
binary: 0011 | ternary: 0,0,-1,0,1
binary: 1011 | ternary: 1,0,-1,0,1
binary: 0111 | ternary: 0,-1,0,0,1
binary: 1111 | ternary: -1,0,0,0,1
binary: 00001 | ternary: 0,0,0,0,1
(4)
整数 の符号付き二進表現における非零桁数の最小値を とし、 とおく。符号を反転すれば である。 最下位桁の偶奇から、
が成り立つ。また、最小表現に または を加え、同じ指数の項を整理すると、 非零項数を高々 増やした表現が得られる。実際、逆符号の同じ項は相殺し、 同符号の二項 は一項 にまとめればよい。 この操作は項数を減らすので有限回で終わる。したがって
これを用いると、
従って、奇数 の最下位桁を選ぶ際、 なら を、 なら を選ぶと、 残りを で割った整数が偶数となり、上の二つの候補のうち最小の重みを達成する。 では一桁の表現を選ぶ。偶数の場合は最下位桁を として で割る。 これは (3) のアルゴリズムであり、奇数の処理の直後には の桁が現れるので疎な表現になる。 残りの整数に関する帰納法により、この表現の重みは である。 よって題意の不等式が成り立つ。
最小の重みを達成する表現自体は一意とは限らない。 例えば では、どちらの表現も重み である。
(5)
長さ の疎な列 (各桁は )の総数を 、その全列にわたる重みの総和を とする。このとき
したがって母関数は
支配的な極 を比較すると
ゆえに である。
-- より、 は最高位が高々 の疎な表現と ちょうど一対一に対応する。最高位が の疎な表現では、その桁は 、第 桁は であり、残る 桁は上記の任意の疎な列である。従って、
と上の漸近式を代入すれば となる。したがって