0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AtCoder Beginner Contest 152

Last updated at Posted at 2020-02-18

###C - Low Elements

$P_{i}$は前すべて数より小さくなければならない。

import sys
n, *p = map(int, sys.stdin.read().split())
c = 0
minp = p[0]
for i in p:
    if i <= minp:
        c += 1
        minp = i
print(c)

###D - Handstand 2

解説をコードで実装する。

n = input()
intn = int(n)
ln = len(n)

if intn < 10:
    print(n)
    quit()


# 先頭の桁の数はiに等しく、末尾の桁の数はjに等しい整数kの数を取る
def count(i, j):
    res = 0
    if i == j:
        res += 1
    if ln == 2:  # 二桁の場合
        if 10 * i + j <= intn:
            res += 1
    else:
        res += (10**(ln - 2) - 1) // 9
        # 例えば、
        # nが三桁の場合、二桁のkが1つ
        # nが四桁の場合、二桁のkが1つ、三桁のkが10つで、合計11つ

        if i < int(n[0]):
            res += 10**(ln - 2)
            # i***j(*の数がln-2)のような形のkが全部とれる

        elif i == int(n[0]):  # n='iabcd'の場合
            tn = int(n[1:-1])  # 'iabcj'の'abc'をとる
            if j <= intn % 10:  # j<=d
                res += tn + 1  # 'i000j'~'iabcj'が全部とれる
            else:
                res += tn  # 'iabcj'がとれない
    return res


res = 0
for i in range(1, 10):
    for j in range(1, 10):
        res += count(i, j) * count(j, i)
print(res)

###E - Flatten

https://atcoder.jp/contests/abc152/submissions/9693323
を参考しました。
Aたちの最小公倍数をとってから、Aのモジュラ逆数をかけてBを求める。
一見すると最速解答だと思えないが、以下2つ関数を心得た。
min_factor:最小素因数を求める。
prime_factorize:素因数分解

import sys
read = sys.stdin.read

N, *A = map(int, read().split())
mod = 10 ** 9 + 7


def min_factor(n):
    sieve = list(range(n + 1))
    sieve[2::2] = [2] * (n // 2)
    for i in range(3, int(n ** 0.5) + 2, 2):
        if sieve[i] == i:
            sieve[i * i::2 * i] = [i] * ((n - i * i) // (2 * i) + 1)
    return sieve


table = min_factor(10**6)  # table[:10] = [0, 1, 2, 3, 2, 5, 2, 7, 2, 3]


def prime_factorize(n):
    a = {}
    while n != 1:
        b = table[n]
        if b in a:
            a[b] += 1
        else:
            a[b] = 1
        n //= b
    return a


# prime_factorize(18) = {2: 1, 3: 2}
# prime_factorize(39) = {3: 1, 13: 1}
dic = {}
for i in A:
    for key, value in prime_factorize(i).items():
        if key in dic:
            dic[key] = max(dic[key], value)
        else:
            dic[key] = value
# 最小公倍数を求める
lcm = 1
for i, j in dic.items():
    lcm *= pow(i, j, mod)
    lcm %= mod

answer = sum(lcm * pow(i, mod - 2, mod) for i in A) % mod
print(answer)

###F - Tree and Constraints
https://atcoder.jp/contests/abc152/submissions/9619555
を参考しました。
私にとってとても難しい。

入力例4を例として挙げる。

8
1 2
2 3
4 3
2 5
6 3
6 7
8 6
5
2 7
3 5
1 6
2 8
7 8

入力中の木は以下のようなものです。
image.png

import numpy as np
import sys
readline = sys.stdin.readline

N = int(readline())
AB = list(list(map(int, readline().split())) for _ in range(N - 1))
M = int(readline())
UV = list(list(map(int, readline().split())) for _ in range(M))

graph = [[] for _ in range(N + 1)]
for i, (a, b) in enumerate(AB):
    graph[a].append((b, i))
    graph[b].append((a, i))



def get_path(U, V):
    INF = 100
    visited = [False] * (N + 1)
    pred = [None] * (N + 1)
    stack = [U]
    visited[U] = True
    while stack:
        v = stack.pop()
        for w, i in graph[v]:
            if visited[w]:
                continue
            visited[w] = True
            pred[w] = (v, i)
            stack.append(w)
    path = 0
    w = V
    while w != U:
        v, i = pred[w]
        w = v
        path += 1 << i
    return path


condition_path = [get_path(u, v) for u, v in UV]
# 2進数の形でuからvに到達するため使った橋を記録する
# 5ペアのuvのpathが、['0110010', '0001010', '0010011', '1010010', '1100000']です。
# '0110010'の意味は「2から7に到達するため2,5,6番目の橋を利用する」


# 2進数nの'1'を数える。popcnt(7)=3,popcnt(9)=1
def popcnt(n):
    c = (n & 0x5555555555555555) + ((n >> 1) & 0x5555555555555555)
    c = (c & 0x3333333333333333) + ((c >> 2) & 0x3333333333333333)
    c = (c & 0x0f0f0f0f0f0f0f0f) + ((c >> 4) & 0x0f0f0f0f0f0f0f0f)
    c = (c & 0x00ff00ff00ff00ff) + ((c >> 8) & 0x00ff00ff00ff00ff)
    c = (c & 0x0000ffff0000ffff) + ((c >> 16) & 0x0000ffff0000ffff)
    c = (c & 0x00000000ffffffff) + ((c >> 32) & 0x00000000ffffffff)
    return c


S = np.zeros(1 << M, np.int64)
sgn = np.ones(1 << M, np.int64)
for i in range(M):
    S[1 << i:1 << (i + 1)] = S[:1 << i] | condition_path[i]
    sgn[1 << i:1 << (i + 1)] = -sgn[:1 << i]

# 一応理解したが、どう説明すればいいか…

# i:制約の満足状況を2進数で表す。例えばi=31が「全部満たす」、i=17が「他の制約に関係なく、制約1,5を満たす」

# S[i]が「状況iで全部白く塗られればならない橋」です。
# S[0]が「すべての制約が不満足な時、全部白く塗られれば大丈夫」、
# i=0の時、S[1] = S[0]|condition_path1 ⇒S[1]が「制約1を満足する時、2,5,6番目の橋が同時白くなれない」、
# i=1の時、S[2,3] = S[0,1]|condition_path2
#   ⇒S[2]が「制約2を満足する時、2,4番目の橋が同時白くなれない」
#   ⇒S[3]が「制約1,2を満足時、2,4,5,6番目の橋が同時白くなれない」、
# …

# sgnが集合の加減法のようなことをやっている。重複計算したら引き算で、引きすぎたらまた足し算。

n_edges = popcnt(S)  # 利用されている橋の数を計算
x = 1 << (N - 1 - n_edges)  # 各状況で「自由橋」の数により塗り方を計算
answer = (x * sgn).sum()

# sgn=[1 -1 -1 1 -1 1 1 -1 -1 1 1 -1 1 -1 -1 1 -1 1 1 -1 1 -1 -1 1 1 -1 -1 1 -1 1 1 -1]
# x = [128 16 32 8 16 8 8 4 16 8 8 4 8 4 4 2 32 88 4 4 4 2 2 8 8 4 4 4 4 2 2]
# すべての塗り方(x[0]=128)から、
# ① 制約1を満足する時、「1,3,4,7番目の橋に関わらず、2,5,6番目の橋が同時白く塗られる」の塗り方(x[1]=16)を引き、
# ② 制約2を満足する時、「1,3,5,6,7番目の橋に関わらず、2,4番目の橋が同時白く塗られる」の塗り方(x[2]=32)を引き、
# ③ でも、①②で「1,3,7番目の橋に関わらず、2,4,5,6番目の橋が同時白く塗られる」の塗り方(x[3]=8)を二回引いてしまった。
#    だからここでx[3]を足すべき。
# …

print(answer)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?