Xmas Contest 2018
A - Art Time
問題
- 与えられた画像で4色塗り分け問題を実践せよ
解法
ペイントで適当に。隣り合うセルに別々の3色が塗られていればそのセルは残りの1色とわかるが、途中でどうしても決められないところが出るので、仮定して進み、仮定した箇所をメモっておく。破綻した時にそこまで戻る、というのを繰り返すと手動全探索が出来る。Ctrl+Zは偉大。
B - Bit Smaller
問題
- $3^4425=34425$ のように、指数を下に下ろしても数が等しくなるような数字を、20181224以下で全列挙せよ
解法
全探索。せいぜい8桁なので、指数の項は多くとも $1^23^45^{67}8$ のよう3つまで。
入力はないので、多少時間かかっても答えをTextで提出すればよい。
さすがに指数部が3桁以上になることは無いだろうと考えて、その条件で証明の無い枝刈り。
後は、切る位置によって'0'が先頭に来る場合は成立しないことに注意。
# もうちょいスッキリ書きたい from itertools import product def test(n, s, c, spl): for sa, sb, tb in spl: str_a = s[sa:sb] str_b = s[sb:tb] if str_a[0] == '0' or str_b[0] == '0': return False c *= pow(int(str_a), int(str_b), 1000000009) if c > n: return False return n == c def make_can(s, t): ms = max(s + 1, t - 2) return [[(s, i, t)] for i in range(ms, t)] def make_cans(): cans = {} for dab in range(2, 8): if dab == 2: can = make_can(0, 2) elif dab == 3: can = make_can(0, 3) elif dab == 4: can = make_can(0, 4) can.extend(a + b for a, b in product(make_can(0, 2), make_can(2, 4))) elif dab == 5: can = make_can(0, 5) can.extend(a + b for a, b in product(make_can(0, 2), make_can(2, 5))) can.extend(a + b for a, b in product(make_can(0, 3), make_can(3, 5))) elif dab == 6: can = make_can(0, 6) can.extend(a + b for a, b in product(make_can(0, 2), make_can(2, 6))) can.extend(a + b for a, b in product(make_can(0, 3), make_can(3, 6))) can.extend(a + b for a, b in product(make_can(0, 4), make_can(4, 6))) can.extend(a + b + c for a, b, c in product(make_can(0, 2), make_can(2, 4), make_can(4, 6))) elif dab == 7: can = make_can(0, 7) can.extend(a + b for a, b in product(make_can(0, 2), make_can(2, 7))) can.extend(a + b for a, b in product(make_can(0, 3), make_can(3, 7))) can.extend(a + b for a, b in product(make_can(0, 4), make_can(4, 7))) can.extend(a + b for a, b in product(make_can(0, 5), make_can(5, 7))) can.extend(a + b + c for a, b, c in product(make_can(0, 2), make_can(2, 4), make_can(4, 7))) can.extend(a + b + c for a, b, c in product(make_can(0, 2), make_can(2, 5), make_can(5, 7))) can.extend(a + b + c for a, b, c in product(make_can(0, 3), make_can(3, 5), make_can(5, 7))) else: raise NotImplementedError cans[dab] = can return cans buf = [] cans = make_cans() print(cans) for n in range(1000000, 20181225): s = str(n) for digit_c in range(1, len(s) - 1): str_c = s[-digit_c:] if str_c[0] == '0': continue c = int(str_c) if n % c != 0: continue dab = len(s) - digit_c for ccc in cans[dab]: if test(n, s, c, ccc): buf.append(s) print(s, ccc) break else: continue break
- $3^4 \times 425=34425$
- $31^2 \times 325=312325$
- $3^4 \times 4250=344250$
- $49^2 \times 205=492205$
- $31^2 \times 3250=3213250$
- $3^4 \times 42500=3442500$
- $3^4 \times 7^2 \times 875=3472875$
- $49^2 \times 2050=4922050$
- $1^3 \times 7^4 \times 5725=13745725$
- $1^3 \times 9^4 \times 2125=13942125$
- $1^4 \times 569^2 \times 45=14569245$
- $1^6 \times 7^4 \times 6975=16746975$
- $1^9 \times 7^4 \times 8225=19748225$
綺麗。
ほとんどは指数部が $3^4=81$ や $7^4=2401$ のように「2を素因数に多く持つ数+1」になり、整数部が5を素因数に多く持つことで、「$10^{3~4}$の倍数+元の整数」となり成立している。
H - Hello, Xmas Contest 2018
問題
- 任意の大きさの盤面のいくつかのマスに文字を書き込む
- 書き込める文字は、'A'~'Z' と '*'
- 各行の、最も左にある文字から、'*' を抜いて読むと、$S$ になる
- 各列の、最も上にある文字から、'*' を抜いて読むと、$T$ になる
- 書き込む必要のある最小マス数を求めよ
例
S = ABCF, T = EBDCA *EBDCA ↓↓↓↓↓↓ *→*E D A→ A B→ B C→ C 7マス書き込めば成立 F→ F
解法
$S$ と $T$ に共通する文字は、必ず共有する位置に置くことができる。(複数回登場する文字は、同じ個数まで)
$(H,W)=(Sの文字数, Tの文字数)$ な盤面を用意して、'A'が $S$ で1文字目、$T$ で5文字目に出てくるなら、$(1,5)$ に'A'を書き込めばよい。
また、共通しない文字や、双方に登場する文字でも片方が多くて溢れるものは、「1文字目以外は」隠せる(もう一方から読まれない位置に置ける)。1文字目の後ろに置けばよい。
どちらかの1文字目がもう一方に出現しなかった場合は'*'で隠す必要があるが、これも1つさえあれば、盤面を1マス広げて $(1,1)$ に置くことで縦横両方に隠すスペースを確保できる。
よって、$\displaystyle \sum_{c=A ... Z}{文字cの登場回数のSとTで多い方}$ をベースとし、$S_0$が$T$に含まれなかったり、$T_0$が$S$に含まれなかった場合のみ、$+1$すればよい。
from string import ascii_uppercase from collections import Counter s = input() t = input() cs = Counter(s) ct = Counter(t) ans = 0 for c in ascii_uppercase: tmp = 0 if c in cs: tmp = cs[c] if c in ct: tmp = max(tmp, ct[c]) ans += tmp if s[0] not in t or t[0] not in s: ans += 1 print(ans)