Naomi's notebook

Naomi's notebook

AtCoder Beginners Selection in Bash 完走


AtCoder Beginners Selection
atcoder.jp

Haskell
naomi-notebook.hatenablog.com
Javascript
naomi-notebook.hatenablog.com

BashでACしていきます。
Bashは触ったこともないし、どういう時に適している言語なのかすらよくわかっていません。以下のサイトを見て、あとは適宜ググりまくってやっていきます…
http://furyo.on-air.ne.jp/linux/bash.html


ABC088B - Card Game for Two以前は(慣れていなかったので)フィルターの形を使わず、ABC088B - Card Game for Two以降はフィルターの形で解いています

PracticeA - Welcome to AtCoder

read a
read b c
read s
echo $((a+b+c)) $s

ABC081A - Placing Marbles

0で始まる数字は8進法だと思われてしまうので以下だとWA

read a
echo $((a%10+(a/10)%10+(a/100)%10))

10進数に直せる。

read a
a=10#$a
echo $((a%10+(a/10)%10+(a/100)%10))

ABC081B - Shift only

標準入力から配列に格納するのをしばらく調べていたけど、実は-aオプションでやってくれるらしい。
ここら辺も見ておくと良さそうメモ
read コマンドの使い方 - 拡張 POSIX シェルスクリプト Advent Calendar 2013 - ダメ出し Blog

read n
read -a a
ans=0
while true;do
    for i in ${!a[@]};do
        if [ $((a[i]%2)) -eq 0 ];then
            a[$i]=$((a[i]/2))
        else
            echo $ans
            exit
        fi
    done
    ans=$((ans+1))
done

ABC087B - Coins

これがTLEマジ?50^3=125000<=10^6しかループしてないんだけど…

read a
read b
read c
read x
ans=0
for i in `seq 0 $a`;do
    for j in `seq 0 $b`;do
        for k in `seq 0 $c`;do
            if [ $((500*i+100*j+50*k)) -eq $x ];then
                ans=$((ans+1))
            fi
        done
    done
done
echo $ans

調べてみたら10^4~10^5くらいしか計算できないみたいです。ええ…

read a
read b
read c
read x
ans=0
for i in `seq 0 $a`;do
    for j in `seq 0 $b`;do
        k=$(( (x-500*i-100*j)/50 ));
        if [ $k -le $c -a $k -ge 0 ];then
            ans=$((ans+1))
        fi
    done
done
echo $ans

ABC083B - Some Sums

これでTLEして(まさか10^4で死んでいる…?)ってなったんですが、関係ない$*1をans=$*2に警告が出ないように直したらACしました。なんでですか?
(追記)
教えていただきました!$*3で、その計算結果のようなコマンドを探して見つかりませんでした、という警告が出るのですが、どうやらそのコマンドを探すのに実は時間がかかっているらしいです。

競プロとかコードゴルフをやっていると警告を無視する人間になりがちですが、本来出ないようにするべきですよね…
WA

read N A B
ans=0
for (( i=1; i<=$N; i++ ));do
    s=$((i%10+(i/10)%10+(i/100)%10+(i/1000)%10+(i/10000)%10))
    if [ $s -le $B -a $s -ge $A ];then
        $((ans+=i))
    fi
done
echo $ans

AC

read N A B
ans=0
for (( i=1; i<=$N; i++ ));do
    s=$((i%10+(i/10)%10+(i/100)%10+(i/1000)%10+(i/10000)%10))
    if [ $s -le $B -a $s -ge $A ];then
        ans=$((ans+i))
    fi
done
echo $ans

ABC088B - Card Game for Two

ここでフィルタを利用した文字列操作に目覚めたので色々工夫し始める
Linuxのテキストフィルタコマンドであそんでみよう - Qiita
フィルタを使用した文字列操作 1 | UNIX & Linux コマンド・シェルスクリプト リファレンス
【 awk 】コマンド(基本編その3)――テキストの加工とパターン処理・BEGIN・ENDとAWKスクリプト:Linux基本コマンドTips(117) - @IT

このあたり参考にした

sed 1d | sed -e 's/ /\n/g' | sort -rn | paste - - | awk 'BEGIN{a=0;b=0}{a+=$1;b+=$2}END{print (a-b)}'

ABC085B - Kagami Mochi

sed 1d | sort -n | uniq | wc -l

ABC085C-Otoshidama

いやフィルター使ってるけどこれはほとんど前半そのままって感じだ

awk 'BEGIN{sum+=0;can=false}{n=$1;y=$2;for(a=0;a<=n;a++)for(b=0;a+b<=n;b++)if(a*10000+b*5000+(n-a-b)*1000==y){print a,b,n-a-b;exit}print "-1 -1 -1"}END{}'

ABC049C - 白昼夢 / Daydream

javascriptと同じく正規表現
注意としては|のor演算子を使うが、そのためには拡張正規表現を使う必要があるため、-Eオプションをつけなければならない。

grep -cE '^(dream|dreamer|erase|eraser)+$' | sed s/1/YES/g | sed s/0/NO/g

ABC086C - Traveling

そういえばgrepの''の中では変数に$をつけなくていいのね
absがないのでめんどくさい(コードゴルフだったらsqrt(x^2)でできます)

sed 1d | awk 'BEGIN{x=0;y=0;t=0;can=0}{
    d=abs(t-$1)-abs(x-$2)-abs(y-$3); 
    t=$1;x=$2;y=$3;
    if(d<0||d%2==1){can++}
    }
    END{if(can)print("No");else print("Yes")}
    function abs(x){return(x<0)?-x:x}'

*1:ans+=i

*2:ans+i

*3:ans+=i