メモ:ランチタイムCTFもくもく会 & 競プロランチ

Feb 18, 2020 23:16 · 1628 words · 4 minute read

最近は昼にCTFやりはじめて(今はpicoCTF2019やってる)、せっかくだし競プロランチとあわせてお昼休みのメモ残しとく。

CTF

caesar - Points: 100

ciphertextの中身を見てみるとpicoCTF{dspttjohuifsvcjdpobqjtwtvk}となってる。 問題名がcaesarだしシーザー暗号というやつっぽいので3つずらすのを試したら不正解だった。 結局26通り試してそれっぽいのを入力して通った。

dont-use-client-side - Points: 100

https://2019shell1.picoctf.com/problem/49886/

とりあえずソースを表示させたらpassを比較してるコードがあったのでそれを読んでパスを復元した。

logon - Points: 100

何も入力しないでSign InしてみるとログインはできるがFlagは表示されてない。cookieにadmin = Falseという値があったのでこれをTrueに変えてリロードしてみるとフラグをゲットできた。

strings it - Points: 100

strings strings | grep -i ctfするとフラグがあった。

【 strings 】コマンド――バイナリファイルの可読部分を表示する:Linux基本コマンドTips(92) - @IT

vault-door-1 - Points: 100

ソースにあるcheckPassword関数を見れば答えがわかった。

what’s a net cat? - Points: 100

netcatコマンドを使う。

$ nc 2019shell1.picoctf.com 49816

where are the robots - Points: 100

タイトル的にrobots.txtかなと思ってURLの最後に/robots.txtをつけてみたら

User-agent: *
Disallow: /0ecd0.html

こうなっていたので/0ecd0.htmlにアクセスするとフラグがあった。

競プロ

A - Placing Marbles

1文字ずつ数値にして足したら光が見えた…。

提出 #10191239 - AtCoder Beginner Contest 081

puts gets.strip.chars.map(&:to_i).inject(:+)

B - Choose Integers

急に5000兆とかでてきて「は?欲しい」て感じだけど、足すのは常にAの倍数なので結局余りは周期的になるからbを上限にして試してみれば光が見えた…。

提出 #10191425 - AtCoder Beginner Contest 060

a, b, c = gets.strip.split.map(&:to_i)

puts (1..b).any? {|i| i * a % b == c} ? "YES" : "NO"

これほんと、”Yes/No”で提出してて1WAくらった。これでぼくはまだビギナーですと胸を張って言える。なんかツールとか使ってたら防げるのかもしれないけど。使ってないのがばれてしまう。原始的にコピペしてサンプルケース試してるとかが。

C - Same Integers

まず+2できるだけする。そのあとのパターンとしては、

  1. 一番大きな数より1小さいものが1つ
  2. 一番大きな数より1小さいものが2つ
  3. 3つとも同じになってる

のどれか。

最初の入力が1 6 3だったとすると、できるだけ+2したあとは5 6 5になってる。
このとき、上の1のパターンで、ここから等しくするためには
5 6 5
↓ (+1 0 +1)
6 6 6
ということで、あと1回の操作でできる。

今度は最初の入力が2 6 3だったときを考えると、できるだけ+2したあとは6 6 5になる。
このとき、上の2のパターンで、ここから全て等しくするためには
6 6 5
↓ (+1 +1 0)
7 7 5
↓ (0 0 +2)
7 7 7
ということで、2回の操作が必要。

この2つのパターンをどう見分けるかがキモになる。
結局は、できるだけ+2するという操作のあとでも偶奇は変わらないのがポイントで、一番大きい数と、それ以外の数(+2する数)の偶奇の一致をみて、いくつ一致してるかによって場合分けすればおけ丸水産。はくつるです。

提出 #10191714 - AtCoder Beginner Contest 093

a, b, c = gets.strip.split.map(&:to_i)
min, mid, max = [a, b, c].sort

ans = (max - mid) / 2 + (max - min) / 2

p = [(max - mid) % 2, (max - min) % 2].inject(&:+)
if p == 1
  puts ans + 2
elsif p == 2
  puts ans + 1
else
  puts ans
end

変数をpとかやるのよくない。
あとこういう

p = [(max - mid) % 2, (max - min) % 2].inject(&:+)

雑に配列にしてsumするのよくやるけど行儀がよくないだろうなと思いながらも癖で書いてしまう。

C - Write and Erase

偶数回登場する数字は打ち消しあってカロリーゼロになるから、奇数個登場するやつを数えればいいような気がして、AC。

提出 #10196043 - AtCoder Beginner Contest 073

n = gets.to_i
an = n.times.map { gets.to_i }

puts an.group_by(&:itself).select { |k, v| v.size.odd? }.count

これなんかもっといい書き方あるのでは?という気もしてる。group_byのコストいかほど?

ランチタイムにあんまりがんばるとお昼から余計に眠くなっちゃうから緩さを心がけたいけども思わず熱中しすぎて昼から脳が完全に沈黙することもありますここだけの話。