yura1685

ARC224の解法記事

A - Attach 00

自明な上界として,$1$ の位と $10$ の位が $0$ の $100K$ が考えられます.よって $K, 2K, \cdots, 100K$ を順番に見ていって確かめれば良いことが分かります.

def check(N):
    s = str(N)
    if len(s) > 1:
        for i in range(len(s)-1):
            if s[i] == s[i+1] == '0':
                return True
    return False

def solve():
    N = int(input())
    ans = N
    while not check(ans):
        ans += N
    print(ans)

T = int(input())
for _ in range(T):
    solve()

B - Adjacent Tiles

$1$ 個のブロックを置くごとに隣接する辺が何本増えるかを考えたときに,ブロックを置く順番を入れ替えると $3$ 本や $4$ 本といった穴を埋めるような操作をしなくても良いことが分かります.すなわち $2$ 本増えるような操作を最大化したくて,(未証明だけど)正方形の形に置いていくのが良さそうなので,実装したら通りました.

from math import isqrt

def solve():
    N = int(input())
    L = isqrt(N) # 最大の正方形の1辺の長さ
    ans = 2 * L * (L - 1) # まずL*Lの正方形を作る
    N -= L * L
    if N == 0: # もうブロックが無いなら終了
        return ans
    if N <= L: # L*(L+1)の長方形に収まる場合
        ans += 2 * N - 1
        return ans
    else:
        ans += 2 * L - 1
        N -= L
        ans += 2 * N - 1
        return ans

T = int(input())
for _ in range(T):
    print(solve())

C - Ascending Labels

なんか上手いことやって構築できそうです.最初に BFS を考えたけど,長さ $4$ のサイクルが反例.次に DFS を考えてみて,反例が思いつかないので実装してみることに.

def solve():
    N, M = list(map(int, input().split()))
    g = [[] for _ in range(N)]
    for _ in range(M):
        u, v = list(map(int, input().split()))
        g[u-1].append(v-1)
        g[v-1].append(u-1)
    ans = [-1] * N
    ans[0] = 0
    def dfs(u):
        for v in g[u]:
            if ans[v] == -1:
                ans[v] = ans[u] + 1
                dfs(v)
    dfs(0)
    for a in ans:
        print(a)

T = int(input())
for _ in range(T):
    solve()

無事 AC が取れました.PyPy の再帰は遅いので stack DFS がメジャーかと思いますが,stack DFS だと落ちるようです.その分 Codon の再帰はデフォルトで再帰上限が無く,かつ十分高速に動作するので再帰を書く際は Codon で書くことをおすすめします.

D - Angst for All Pairs

ある正の整数 $k$ について $1 \sim N$ のカードに 書く / 書かない はビット列で表現することが出来ます.これを $\mathrm{mask}(k)$ と書くことにします.すると,問題文中の条件は次のように言い換えることが出来ます.

$\iff$

すなわち,$1, 2, \cdots, K$ に対して $0, 1, \cdots, 2^{N} - 1$ を Unique に割り当てられれば良いです.$K$ の大きい方が桁数は大きいので,$K$ は降順に,$\mathrm{mask}$ は $\mathrm{popcount}$ の昇順に割り当てるのが最適であると分かります. 意外にも $\sum{K_i},\ \sum{N_i} \le 10 ^ 6$ なので,面倒なことをせず実装できました(無駄に $K$ が大きくなくて良かった).

from math import comb

def solve():
    N, K = map(int, input().split())
    ans = 0
    if N < 20 and pow(2, N) < K:
        print(-1)
        return 
    w = 1
    r = comb(N, w)
    for i in range(K-1, 0, -1):
        if r == 0:
            w += 1
            r = comb(N, w)
        ans += len(str(i)) * w
        r -= 1
    print(ans)

T = int(input())
for _ in range(T):
    solve()

E - ABC|AB|A

如何にも stack をやってくださいというような問題.$\mathrm{ABC}$ が消せるならば $\mathrm{AB}$ は消せるので,なるべく $\mathrm{ABC} > \mathrm{AB} > \mathrm{A}$ の優先順位で消していきたいです.最初は「前から stack に追加して,$\mathrm{ABC}$ が完成したら削除する」と実装していたのですが,$\mathrm{AABBC}$ のようなケースで消せなくなってしまいます.ここで,$\mathrm{ABB}$ について考えると,前の $\mathrm{AB}$ は後ろに $\mathrm{B}$ がいるせいで,絶対に $\mathrm{ABC}$ の形になることはありません.なので,この $\mathrm{AB}$ は消しても問題ありません.というようなことを沢山やると,無事 AC できました.

def solve():
    S = input()
    stack = []
    for s in S:
        if s == 'A':
            stack.append(s)
        elif s == 'B':
            if stack:
                while stack and stack[-1] == 'AB':
                    stack.pop()
                if stack and stack[-1] == 'A':
                    stack.pop()
                    stack.append('AB')
                else:
                    stack.append('B')
            else:
                stack.append('B')
        else:
            while stack and stack[-1] == 'A':
                stack.pop()
            if stack:
                if stack[-1] == 'AB':
                    stack.pop()
                else:
                    stack.append('C')
            else:
                stack.append('C')
    ans = 0
    for s in stack:
        if s == 'B' or s == 'C':
            ans += 1
    print(ans)

T = int(input())
for _ in range(T):
    solve()