テービーテックのデータサイエンス

未経験リケジョがゼロからデータサイエンティストを目指す姿を記す奮闘記です。2019/12/05文系出身者が共同で更新を開始

TAG index

AtCoderに挑戦~AtCoder Beginners Selection~

f:id:tbtech:20210625130300p:plain
前回の続き!
AtCoder Beginners Selectionに挑戦していきます。

ABC083B - Some Sums

問題文
1 以上 N 以下の整数のうち、10 進法での各桁の和が A 以上 B 以下であるものの総和を求めてください。

n, a, b = map(int, input().split())
result=0
for n in range(1,n+1):
  s = sum(list(map(int, str(n))))
  if a <= s <= b:
    result += n
print(result)

入力値を受け取り、resultという変数を初期値0で準備します。
1以上N以下の数をforで順に取り出し、
str(n)で文字列にした後、各桁の数をintに変換しながらリストへ格納します。
そのリストの合計値をsへ入れて、
ifでsがa以上b以下であれば、resultにsを加算します。
forが終わったら、resultの最終値を出力します。

ABC088B - Card Game for Two

問題文
N 枚のカードがあります. i 枚目のカードには, ai という数が書かれています.
Alice と Bob は, これらのカードを使ってゲームを行います.
ゲームでは, Alice と Bob が交互に 1 枚ずつカードを取っていきます. Alice が先にカードを取ります.
2 人がすべてのカードを取ったときゲームは終了し, 取ったカードの数の合計がその人の得点になります.
2 人とも自分の得点を最大化するように最適な戦略を取った時, Alice は Bob より何点多く取るか求めてください.

num = int(input())
card = list(map(int, input().split()))
card.sort(reverse=True)
print(sum([x for i,x in enumerate(card) if i%2==0])-sum([x for i,x in enumerate(card) if i%2==1]))

入力値を受け取り、cardに各カードの数をリストで格納します。
cardを数が降順になるようreverse=Trueとして並び替えます。
Aliceが先にカードを選択するため、大きいカードからAlice,Bob,Alice,Bob...と順と取ることになるので
奇数番目のカードがAlice、偶数番目がBobのカードになります。
この順番でカードの数を合計して、Aliceの合計からBobの合計を引き、それを出力します。

ABC085B - Kagami Mochi

問題文
X 段重ねの鏡餅 (X≥1) とは、X 枚の円形の餅を縦に積み重ねたものであって、
どの餅もその真下の餅より直径が小さい(一番下の餅を除く)もののことです。
例えば、直径 10、8、6 センチメートルの餅をこの順に下から積み重ねると
3 段重ねの鏡餅になり、餅を一枚だけ置くと 1 段重ねの鏡餅になります。
ダックスフンドのルンルンは N 枚の円形の餅を持っていて、
そのうち i 枚目の餅の直径は di センチメートルです。
これらの餅のうち一部または全部を使って鏡餅を作るとき、最大で何段重ねの鏡餅を作ることができるでしょうか。

N, *D = map(int, open(0).read().split())
print(len(set(D)))

各餅の大きさをDにリストで格納します。
餅は同じ大きさは重ねることができませんが、そうでない餅は下か上に重ねることができます。
なので、重複しない餅の数を数えるだけなので、setに入れると固有値が抽出できて
それの個数をlenで出力します。

ABC085C - Otoshidama

問題文
日本でよく使われる紙幣は、10000 円札、5000 円札、1000 円札です。
以下、「お札」とはこれらのみを指します。青橋くんが言うには、彼が祖父から
受け取ったお年玉袋にはお札が N 枚入っていて、合計で Y 円だったそうですが、
嘘かもしれません。このような状況がありうるか判定し、
ありうる場合はお年玉袋の中身の候補を一つ見つけてください。
なお、彼の祖父は十分裕福であり、お年玉袋は十分大きかったものとします。

n, y = map(int, input().split())
for i in range(n + 1):
  for j in range(n - i + 1):
    if i * 10000 + j * 5000 + (n - i - j) * 1000 == y:
      print(i, j, n - i - j)
      exit()
print("-1 -1 -1")

nにお札の枚数、yに合計値を入れてこれが成り立つかどうか調べます。
10000円札をi枚、5000円札をj枚とすると、1000円札はn-i-j枚となります。
これをforで順に1枚づつ増やしてその合計値がyになったら、各枚数を出力します。
合計値がyにならなかった場合は、(-1-1-1)を出力します。

ABC049C - 白昼夢

問題文
英小文字からなる文字列 S が与えられます。 Tが空文字列である状態から始め、
以下の操作を好きな回数繰り返すことで S=T とすることができるか判定してください。T の末尾に dream dreamer erase eraser のいずれかを追加する。

s = input().replace("eraser","").replace("erase","").replace("dreamer","").replace("dream","")
if s:
  print("NO")
else:
  print("YES")

1行目は、入力値の文字列内に[eraser,erase,dreamer,dream]が含まれる場合は削除して
残った文字列をsへ入れています。ただし消す順番を間違えないよう注意してください。
こうすることで、もしsに文字が入っていればS=Tが成り立たないことがわかります。
よってsに文字があればNOと出力し、そうでなければYESと出力します。

ABC086C - Traveling

問題文
シカのAtCoDeerくんは二次元平面上で旅行をしようとしています。
AtCoDeerくんの旅行プランでは、時刻 0 に 点 (0,0) を出発し、
1 以上 N 以下の各 i に対し、時刻 ti に 点 (xi,yi) を訪れる予定です。
AtCoDeerくんが時刻 t に 点 (x,y) にいる時、 時刻 t+1 には 点 (x+1,y), (x−1,y), (x,y+1), (x,y−1) のうちいずれかに存在することができます。
その場にとどまることは出来ないことに注意してください。
AtCoDeerくんの旅行プランが実行可能かどうか判定してください。

n = int(input())
for i in range(n):
  t, x, y = map(int, input().split())
  if x + y > t or (x + y + t) % 2:
    print("No")
    exit()
print("Yes")

n回の移動先を読み取るため、forで各t,x,yを入力します。
旅行プランが不可能になる場合を考えます。
1tの間に動ける距離はxかy方向に1づつまので、x+yがtを超えると不可能になります。
また、x+yが偶数の場合tは偶数、x+yが奇数ならtも奇数でなければいけないので
x+y+tが2で割り切れない場合も、旅行プランが不可能になるのでNOと出力します。
上記の条件に当てはまらなければ旅行プランが可能になり、YESと出力します。

まとめ

AtCoder Beginners Selectionを解き終わりましたが、後半の問題は難しかったです!
難しく考えてコードが長くなると時間オーバーになってしまいました。
解説などを見るとすっきりしたコードばかりで、
まず問題を簡潔に捉える必要があることがわかりました。
これからも練習問題に励み、ゆくゆくはコンテストに参加したいと思います(*^ω^*)