天色グラフィティ

技術ちっくなことを書きます

ARC099に参加した(210位)

f:id:ejinote:20180624151041p:plain

ARC099に参加しました。210位でレートは1304→1429になりました。 久しぶりのコンテスト参加で緊張しましたが、Dをそれなりに早く解いたのがよかったっぽいです。

そういえば先日書いた記事がホッテントリに載りました。結構うれしいものですね。

amalog.hateblo.jp

振り返り

C - Minimization

  • 最小値が1なので、全要素を1にすればよい
  • 1回適用すると1がK-1個増える

1を中心に左右に1を広げていくイメージで解きました。1の左右それぞれについて端から最適な回数で処理をして、1の周りの余りはよしなにやる感じ。

import math
n, k = map(int, input().split())
A = list(map(int ,input().split()))
print(math.ceil((n-k)/(k-1)+1))

D - Snuke Numbers

手で書いても全く分からなかったので実験しました。

import matplotlib.pyplot as plt
%matplotlib inline

def digit_sum(i):
    return sum(map(int, list(str(i))))

scores = [i/digit_sum(i) for i in range(1, 50000)]
plt.figure(figsize=(10, 5))
plt.scatter(list(range(1, 50000)), scores, s=1)
plt.show()

f:id:ejinote:20180625171837p:plain

規則性があることがわかります。ちなみにスコアがジャンプするのは繰り上がりが起きるときなので、XXX999みたいな数にだけ着目すればよいと分かります。

XXX999みたいな数それぞれについて、次のやつとの比較を行って、だめだったら消せば良いと思います。

実装は鬼汚いです。

def digit_sum(i):
    return sum(map(int, list(str(i))))

def score(head, tail):
    return num(head, tail)/digit_sum(num(head, tail))

def num(head, tail):
    return int(str(head)+tail)

k = int(input())
tail = ''
head = 0
cnt = 0
last = 0
while True:
    head += 1
    if score(head, tail) <= score(head+1, tail):
        if num(head, tail) > last:
            print(str(head)+tail)
            last = num(head, tail)
            cnt += 1
            if cnt == k:
                break
    else:
        head = 0
        tail += '9'

E - Independence

  • 辺をできるだけ少なく切断して2つのクリーク(部分グラフがすべて完全なグラフ)に分割すればよい
  • 補グラフを取ると少し見通しが良くなって、補グラフにできるだけたくさん辺を足して完全二部グラフにする問題に変換することができる
  • 補グラフをとった時点で二部グラフでなければ達成不可能。
  • 辺はいくつでも足していいので、補グラフを連結成分分解して成分の集合を2つにまとめて完全二部グラフにすることができる。
  • クリークの辺の数は頂点数で決まり、辺を多くするなら頂点を多くすれば良い。ただ、頂点集合が2つあるので、2つをできるだけ同じサイズにすればよい。
  • うまいまとめかたを探すためにDP

みたいな感じで解けると思います。僕は実装が間に合いませんでした。

感想

Dが早く解けたのでレートもあがり万々歳です。たのしいですね。

そろそろ証明からは逃れられなそうなので、普段から軽く証明することは意識したいと思います。