パナソニックプログラミングコンテスト(AtCoder Beginner Contest 195)

橙 perf 域から外れてしまった.

A - Health M Death

H % M == 0 ? "Yes" : "No"

B - Many Oranges

個数  k を決め打って,実現可能かどうかを考える. k 個のみかんの重さとしてあり得る最小値  L_k L _ k =kA で,最大値  R _ k R _ k = kB である.従って, L _ k \leq W \leq R _ k が実現可能であるための必要条件である.実はこれは十分条件にもなっている.

理由としては,すべてのみかんの重みを  \dfrac{W}{k} にすれば, A\leq \dfrac{W}{k} \leq B かつ  \displaystyle\sum _ {i=1} ^ k \dfrac{W}{k}=W が成立するためである.

なお,みかんの重みが整数に限られている場合でも,全てのみかんの重みを  \left\lfloor\dfrac{W}{k}\right\rfloor にしてから, W-k\cdot\left\lfloor\dfrac{W}{k}\right\rfloor 個のみかんの重みを  +1 してあげればよい. W=kB の場合は  +1 すると  B より大きくなってしまうが,このとき  W-k\cdot\left\lfloor\dfrac{W}{k}\right\rfloor=0 なので問題ない.

C - Comma

まず, d 桁の数に打つコンマの数は  \left\lfloor\dfrac{d - 1}{3}\right\rfloor である.

 N の桁数を  L とすると, d=1,\ldots,L-1 桁の任意の数は  N 以下であり,各  d に対して  10 ^ d - 10 ^ {d - 1} 個存在する.

また, L 桁でかつ  N 以下の数の個数は  N+1-10 ^ {L-1} である.

以上より,求める答えは以下のように表せる.

 \displaystyle
\sum_{d=1}^{L-1}\left\lfloor\dfrac{d - 1}{3}\right\rfloor\cdot\left(10^d-10^{d-1}\right)+\left\lfloor\dfrac{L - 1}{3}\right\rfloor\cdot\left(N+1-10^{L-1}\right)

D - Shipping Center

まず,クエリ毎に解法を考えてみる.

使える箱の個数を  K とする.価値の高い順に,箱のサイズが出来るだけ小さいものを選択して荷物を入れていくという貪欲法により解くことが出来る.

このような貪欲法を考えるのは,直感的には以下のような理由による.

  • 先に価値の低い荷物が箱を使ってしまった場合,後から価値の高い荷物を入れる箱がなくなってしまって損する可能性がある
  • 先に大きい箱を使ってしまった場合,後で大きい荷物が来た場合に入れられなくなって損する可能性がある

クエリ毎の計算量は,荷物のソートを事前に済ませておけば入れる箱を毎回線形探索しても  O(NM) である.従って,全体  O(N\log N + QNM) でこの問題を解くことが出来る.

E - Lucky 7 Battle

次のような DP を考える.

 \displaystyle
\mathrm{dp}[i][j]=\text{残り $i$ ターンで $T \equiv j\;(\mathrm{mod}\ 7)$ であるとき,高橋君は勝つことができるか}

ゲームのルールから, i=0 の場合に関して以下が成り立つ.

 \displaystyle
\mathrm{dp}[0][j]=\begin{cases}
\mathrm{True} & j=0\\
\mathrm{False} & j=1,\ldots,6
\end{cases}

ゲームを後ろから見る関係上,以降は  X および  S を反転しておくことにする

残り  i ターンの時点で  d が加えられた場合, j の値は  j+d\cdot 10 ^ {i-1} \bmod 7 へと変化する.従って,DP の遷移は次のように書くことが出来る.

 \displaystyle
\mathrm{dp}[i][j]=\begin{cases}
\mathrm{dp}[i-1][j]\lor\mathrm{dp}[i-1][j+S_i\cdot 10^{i-1} \bmod 7]& \text{if $X_i=\text{'T'}$} \\
\mathrm{dp}[i-1][j]\land\mathrm{dp}[i-1][j+S_i\cdot 10^{i-1} \bmod 7] &\text{if $X_i=\text{'A'}$}
\end{cases}

答えは, \mathrm{dp}[N][0] \mathrm{True} なら高橋君,そうでなければ青木君である.

F - Coprime Present

未証明.追加可能な数の集合を状態としてメモ化再帰をすると間に合って解ける.

from math import gcd

A, B = map(int, input().split())
W = B - A + 1
coprime = [[i < j and gcd(A + i, A + j) == 1 for j in range(W)] for i in range(W)]
memo = {}

def dfs(s):
    if s in memo:
        return memo[s]
    res = 1
    bits = [i for i in range(W) if s >> i & 1]
    for i in bits:
        t = 0
        for j in bits:
            t |= coprime[i][j] << j
        res += dfs(t)
    memo[s] = res
    return res

print(dfs((1 << W) - 1))

functools.lru_cache を使えばメモ用の dict を持たなくてもよい.

from functools import lru_cache
from math import gcd

A, B = map(int, input().split())
W = B - A + 1
coprime = [[i < j and gcd(A + i, A + j) == 1 for j in range(W)] for i in range(W)]

@lru_cache(maxsize=1 << 32)
def dfs(s):
    res = 1
    bits = [i for i in range(W) if s >> i & 1]
    for i in bits:
        t = 0
        for j in bits:
            t |= coprime[i][j] << j
        res += dfs(t)
    return res

print(dfs((1 << W) - 1))