diverta 2019 Programming Contest

残念、Unratedになってしまった。運営の方々お疲れ様です。

atcoder.jp

例のごとく、assertの量がドはまり感を醸し出す。 まず、”AB"が含まれている場合はよい。で、単に末尾のAと先頭のBだけでなく、両方とも満たす場合は別に考える必要がある。

ここからABの数を数えるときに両側にあるものを1列に並べることで、並べた個数をCとしたとき、C-1個の"AB"を作ることができる。

ここまではよかった。では、これと残りの末尾のA、先頭のBをどう組み合わせるかで微妙な勘違いをしてはまった。

回答的には単にCを並べているかどうか、a,bがあるかだけで、判断すればよい。

最後にaのみ、bのみを少ないほうに合わせた数でABができるのでそれを足す。

def solve(N, Ss):
    a = 0
    b = 0
    both = 0
    ans = 0
    for s in Ss:
        ans += s.count("AB")
        if s[-1] == "A" and s[0] == "B":
            both += 1
        else:
            if s[-1] == "A":
                a += 1
            if s[0] == "B":
                b += 1

    if both > 0:
        ans += both - 1

    if both > 0 and a > 0:
        ans += 1
        a -= 1

    if both > 0 and b > 0:
        ans += 1
        b -= 1

    ans += min(a, b)
    return ans


assert (solve(1, ["AB"]) == 1)
assert (solve(2, ["AB", "ABABAB"]) == 4)
assert (solve(2, ["AB", "ABABAB"]) == 4)
assert (solve(2, ["CCB", "CCB"]) == 0)
assert (solve(1, ["CABC"]) == 1)
assert (solve(2, ["CCA", "BCC"]) == 1)
assert (solve(4, ["CCA", "BCC", "CCA", "BCC"]) == 2)
assert (solve(3, ["CCA", "BCC", "CCA"]) == 1)
assert (solve(200, ["CCA"] * 100 + ["BCC"] * 100) == 100)
assert (solve(200, ["CCA"] * 110 + ["BCC"] * 90) == 90)
assert (solve(200, ["CCA"] * 90 + ["BCC"] * 110) == 90)
assert (solve(200, ["ABA"] * 90 + ["BCC"] * 110) == 90 + 90)
assert (solve(200, ["ABA"] * 90 + ["BCC"] * 110) == 90 + 90)
assert (solve(200, ["CCA"] * 110 + ["BAB"] * 90) == 90 + 90)
assert (solve(200, ["CCA"] * 90 + ["BAB"] * 110) == 90 + 110)
assert (solve(2, ["ABA", "BAB"]) == 3)
assert (solve(200, ["ABA", "BAB"] * 200) == 3 * 200)
assert (solve(2, ["ABB", "AAB"]) == 2)
assert (solve(200, ["ABB", "AAB"] * 100) == 200)
assert (solve(2, ["ACA", "BCB"]) == 1)
assert (solve(2, ["ACB", "BCA"]) == 0)
assert (solve(2, ["BCB", "BCA"]) == 1)
assert (solve(2, ["BCB", "ACA"]) == 1)

assert (solve(4, ["BCA", "BCA", "CA", "BC"]) == 3)
assert (solve(6, ["BCA", "BCA", "CA", "BC"] + ["CC", "CC"]) == 3)
assert (solve(4 * 2, ["BCA", "BCA", "CA", "BC"] * 2) == 6)
assert (solve(6, ["BCA", "CA", "BC"] * 2) == 4)

assert (solve(2, ["A", "B"]) == 1)
assert (solve(2, ["AA", "BB"]) == 1)
assert (solve(2, ["AAB", "BB"]) == 1)
assert (solve(2, ["AACB", "BB"]) == 0)
assert (solve(3, ["AACB", "BB", "AA"]) == 1)
assert (solve(300, ["BA", "BA", "BA"] * 100) == 299)
assert (solve(300, ["BABA", "BABA", "BABA"] * 100) == 299 + 300)
assert (solve(400, ["BABA", "BABA", "BABA", "AA"] * 100) == 299 + 300 + 1)
assert (solve(4, ["AA", "BA", "BA", "BB"]) == 3)
assert (solve(3, ["AB", "BB", "AA"]) == 2)
assert (solve(3, ["AB", "BA", "AA"]) == 2)
assert (solve(3, ["AB", "BA", "BA"]) == 2)
assert (solve(4, ["AB", "BA", "BA", "AA"]) == 3)
assert (solve(4, ["AB", "BA", "BA", "BB"]) == 3)
assert (solve(3, ["AB", "BA", "BB"]) == 2)
assert (solve(3, ["AB", "AA", "BB"]) == 2)
assert (solve(2, ["AB", "BA"]) == 1)
assert (solve(2, ["BA", "BA"]) == 1)
assert (solve(3, ["AB", "BA", "BA"]) == 2)
assert (solve(3, ["BA", "BA", "BA"]) == 2)
assert (solve(3, ["BCA", "BCA", "BCA"]) == 2)
assert (solve(3, ["BCC", "BCA", "BCA"]) == 2)
assert (solve(3, ["CCA", "BCA", "BCA"]) == 2)

print("OK")
if __name__ == "__main__":
    N = int(input())
    Ss = [input() for _ in range(N)]
    print(solve(N, Ss))

atcoder.jp

これも約数を求めてカウントすればよい、というところまではすぐに分かったがどうも実装がはまった。

まず、約数を求める範囲だが、

N = m * k + k 

としたとき、例にもあるようにN=8のときm = 7になるため、mを動かしてしまうと調べる範囲がどうも1 - Nの範囲になり間に合わない。

そこで、逆にkを動かそうと考えてみると、

N = m * k + k 
    = (m + 1) * k 

より、一つのkに対して、一つのmが定まることがわかる。

この式を満たすkを探すことを考えれば、考えられるすべてのkを求めるためにはO(√N)ですむ。

(N // k) - 1 = m
def solve(N):
    s = 1
    e = int(pow(N, 0.5)) + 1
    ds = []
    for k in range(s, e):
        if N % k == 0:
            m = (N // k) - 1
            if m and N // m == N % m:
                ds.append(m)
 
    return sum(ds)


assert (solve(8) == 3 + 7)
assert (solve(10) == 4 + 9)
assert (solve(1000000000000) == 2499686339916)
if __name__ == "__main__":
    N = int(input())
    print(solve(N))