Python
AtCoder
python3
競技プログラミング

AtCoderの過去問をPythonで解く(解けるとは言っていない)#ABC100

まえおき

勉強の為にやっているので、ググったり時には解説読みながらやっております。
ご了承ください。

A問題:Happy Birthday!

問題文からして、AとBが共に8以下である必要がある。

Birthday.py
a,b = map(int,input().split())
if (a <= 8) and (b <= 8):
    print('Yay!')
else:
    print(':(')

B問題:Ringo's Favorite Numbers

Nを100^D倍するだけだな!

Numbers.py
D,N = map(int,input().split())
print(N*(100**D))

当然のようにWAした。
N = 100 の時に割れる回数が一回増えてしまうので、条件を満たさなくなってしまうことを見落としていた。
本当は一般化した方が良いのだろうけど、今回は問題の制約がN ≦ 100なので

Numbers2.py
D,N = map(int,input().split())
if N == 100: N += 1
print(N*(100**D))

これでよかろう。

C問題:*3 or /2

少し考えて、3倍は気にする必要がなく、何回2で割れるかを数えるだけと気づいた。

/2.py
num = int(input())
lis = list(map(int,input().split()))

ans = 0
for i in range(num):
    while lis[i]%2 == 0:
        lis[i] = lis[i]/2
        ans += 1
print(ans)

もっと良い書き方あるかなー。

他の方の回答を見てみる

似てるやつ

/2'.py
num = int(input())
lis = map(int,input().split())

ans = 0
for number in lis:
    while number%2 == 0:
        number /= 2
        ans += 1

・一旦リストにしてインデックスでアクセスするより直接イテレータとして使ったほうが良い。
・なのでmapオブジェクトをlist()する必要もない。
・あれ?最初のinput()も必要なくね?

全然違うやつ

/2''.py
input();print(sum(bin(i)[::-1].index('1') for i in map(int,input().split())))

ワンライナーで書けるのかー。
内包表記がとてもPythonっぽい。
初見だと意味がわからなかったので調べてみた。

input();で標準入力の1行目をスキップしている。
map(int,input().split())の部分がイテレータ。
sum()の引数が内包表記になっている。
bin(i)[::-1]で要素を2進数にして逆順にしている。
.index('1')で何文字目に1が最初に出てくるか=何回2で割れるか。

とても勉強になりますね。
ビット演算はそこそこ頻出らしいので押さえておきたい。

D問題:Patisserie ABC

うーん、わからん。方針すらわからん。
D問題はまだまだ手が付けられそうにないので、解説と解答例を見ていくことにする。

Patisserie.py
from itertools import product
n,m = map(int,input().split())
cake = [list(map(int,input().split())) for i in range(n)]

ans = 0
for x,y,z in product([1,-1], repeat = 3):
    tmp = []
    for a,b,c in cake:
        tmp.append(a * x + b * y + c * z)
    tmp.sort(reverse= True)
    ans = max(ans,sum(tmp[:m]))
print(ans)

他にもっと早いのも短いのもあるけども、可読性はこれが一番な気がした。

itertools.product()でデカルト積を生成
 詳しい説明はここを参考にしました。

product
product([1,-1], repeat = 3)
<itertools.product at 0x1ffc0b60708>

list(product([1,-1], repeat = 3))
[( 1,  1,  1),
 ( 1,  1, -1),
 ( 1, -1,  1),
 ( 1, -1, -1),
 (-1,  1,  1),
 (-1,  1, -1),
 (-1, -1,  1),
 (-1, -1, -1)]

こんなリストを生成しているようです。

cake
#標準入力
5 3
1 -2 3
-4 5 -6
7 -8 -9
-10 11 -12
13 -14 15

n,m = map(int,input().split())
cake = [list(map(int,input().split())) for i in range(n)]
print(cake)
[[1, -2, 3],
 [-4, 5, -6],
 [7, -8, 9],
 [-10, 11, -12],
 [13, -14, 15]]

こちらでは各ケーキのプロパティを二次元配列にしている。
これらを掛け合わせて8通りの全探索をする。
2重for文で同じインデックスの要素を掛けて足してtmpappend()して降順ソートしてm個足す。

sum(tmp[:m])はとてもオシャレでいいですね。
ans = max(ans, x)も便利そうです。
if ans < x:ans = xみたいなことせずに済みそう。

やはり他人のコード読むのが一番勉強になる。
P○izaは課金しないと模範解答見れないのでやはりAtCoderが良いのかな。