演算子の優先順位とか
ビット演算と比較を一緒にすると、比較が先に行われてしまうので括弧で括るのに2B増えてしまう。
なんとか括弧を取りたいんだけどなあ。
優先順位とか結合規則とかもっとよく知る必要があると思った。
あ、全部ビット演算でやればいいのか!
show the way
変数cにstrrchrを動かした時に計算した結果を入れておくようにした。
変数cはループ初回では使われないので都合もいい。
おかげで出力時の判定の部分が削れて3B縮んだ。現在124B。
もっと工夫すれば縮むのかな。
c, j; main(i, m) { for(read(0, &m, 111); j <= (m & 15); j++ && puts(c > 0 ? c > 9 ? "top" : "left" : c < - 9 ? "bottom" : "right"), c = i) c -= i = strrchr(&m, j + 48); }
AOJ難しい
id:incrementさんがYes, I have a numberでゴルフしていたのを見て、ひょっとしたらもっと縮められるかもと思ってやってみました。
が、ことごとくWrong Answerという結果にorz
anarchy golfだったら通ってそうなコードは全部駄目。
通らねえコードはただの文字列だ。うぐぐ。
惨敗したのでやったことだけ残しておこう・・・
追記
空白が連続した場合に0と出力する。
っていうケースを全く考慮してなかったので、通らないのは当たり前でしたorz
意図せず空白が連続した場合に0と出力する場合もあるけど、改行の後に空白が連続したりすると正しく動かない。
なので、以下完全敗北したログになります。ちくしょおおお。
main(i) { for(; i; i == 'DNE' ? i = 0 : printf("%d", strlen(&i))) scanf("%s",&i); }
まずはscanfとstrlenの組み合わせ。
%sで読み込むとスペース区切りで読み込んでくれるのでこの問題にはぴったり。ただ、見ての通り改行できない。
改行コードも読み飛ばされてしまうので、改行する場所の判定ができないという悲しい結果に。
サンプルテストケースと同じテストだといいなと祈りつつ、無理やり改行するようにしてみても当然通らない。
結局欠陥が大きいのでこのコードはボツ。短くなりそうだったんだけどな・・・
j; main(i) { for(; i; i == 69 ? i = 0 : i == 32 | i == 10 ? printf(i == 32 ? "%d" : "%d\n", j), j = 0 : j++) scanf("%c", &i); }
anarchy golfだったら通ってそうなコード。
END OF INPUTのEだけ狙い撃ちして通そうと思った。けど無理でしたorz
NとDも試したけどWrong Answer。コードサイズを大きくして\nEやEN、NDなども試してもWrong Answer。
92Bが狙えただけ落胆も大きい。がっくり・・・
j, k; main(i) { for(; i; i == 32 | i == 10 ? printf( i == 32 ? "%d" : "%d\n", j), j = 0 : (j++, k = (k << 8) + i, (k & 'ooo') == 'END' && i = 0)) scanf("%c",&i);}
上のコードを改良して、形振り構わず通すことだけを考えたコード。
ビットシフトしながら文字を連結して4文字まで保存できるようにしてみた。
我ながらちょっとかっこいいコードが書けたかなとうっとりしてたら通らなかった。あばば。
小文字のoがいい感じのビットマスクに使えそうだったのでENDの取り出しに使う。
何・・・?ENDで終了してもWrong Answer・・・だと・・・?
判定厳しいっすねorz
他にもstrtokやstrchrも試してみるも、これもまた改行が判定できなかったり改行を判定するとコードが大きくなったりしてボツ。
AOJでゴルフするのは難しい。anarchy golfとは別のテクニックが必要だなあ。
正答率が高いか100%正解を返すコードを書きつつ短縮するのは凄い。
答えを埋め込んだりして縮めるのが好きな自分的には中々厳しい環境です・・・
SRM455 DIV2
なんか今回のSRMは説明不足な印象を受けた。
解けている人は結構居たので、単に英語が読めてないか意味が理解できてないだけかもしれないけどorz
0点なのにrateは変動無し。低rate組で良かった!
なんか悲しい・・・
追記
意味が理解できてないだけでしたorz
英語もっと勉強しないと・・・
250
意味不明。解読不可能。
グリッドの大きさはどれくらい?クモはどこからスタートするの?
どこまで行ったら床に落ちるの?
チャレンジで落とせそうなコードを見つけたけど、正しい結果の出し方がわからないのでチャレンジできず。
なんか悔しい。
500
数列のAとBが与えられる。規定の手順に従って計算してできた数列の中から、Bの数列が出てくるのは何番目かっていう問題。
出てこない場合は-1を返せとのことだけど、どこまで計算した結果出てこないと判断すればいいのかわからない・・・
悩んでても仕方ないのでとりあえずコーディング開始。
でも提出できるレベルには仕上がらずに終了。
意味がわからないなら考えてないでできそうな部分からやっていけばよかったかな。
と今になって思う。って前も書いてる気がする・・・あれ?
順調順調
短いコードを書くためのセオリーみたいのを押さえると順調に縮む。
後は良いアルゴリズムを思いつけるかどうか。
もっと頭よくなーれ。
show the way
前回提出したものからせこせこ削って127Bまで短縮できた。
重複している部分を取り除いただけでも短くなったけど、やっぱり配列を廃止できるとぐっと縮む。
int型の変数に1Bづつアクセスしたいならchar型で受け取る関数を使えばいいじゃない。
ということで番号を探すのにstrrchrを使う。
対象が見つかった最後の場所を返してくれるので、最初の1Bを読み飛ばさなくていいのも美味しい。
後はASCIIコードの0〜9の下位4ビットはそのまま数値の0〜9になっているので、ANDを取って下位4ビットだけ取り出す。
普通に計算するコードでは、今のところこれが最短なのではないかなと思うけどどうなんだろう。
ループで探していたときのコードもおまけにぺたっと。
137B版
char m[112]; c, j; main(i) { for(read(0, m, 111); j < *m - 47;) m[i] == j + 48 ? c && puts(c - i > 0 ? c - i > 9 ? "top" : "left" : c - i < -9 ? "bottom" : "right"), c = i, i = 1, j++ : i++; }
127B版
c, j; main(i, m) { for(read(0, &m, 111); j <= (m & 15); j++ && puts(c - i > 0 ? c - i > 9 ? "top" : "left" : c - i < -9 ? "bottom" : "right"), c = i) i = strrchr(&m, j + 48); }
ちなみに何故か127Bのコードは手元の環境では上手く動かない。
最後の行だけ上手く取得できてないようだ。なんでだろう?
SRM454 DIV2
折角ポイントできたものをつまらないミスで落としたorz
順調にrate降下中。次回は少しでも上げて行きたいなあ。
焦らず確実に、でも素早くっていうのに慣れたい。
250
ABCと3つの値が与えられる。入力された数値それぞれの各桁の値を足し算した数値を求め
A以上B以下の値で、Cに一番近く一番小さい数値を出力しろっていう問題。
しばらくこの意味がわからずに英文とにらめっこ。
ループの数が多くなりそうだったので、メモ化しながら書いては試し書いては試ししてたらコードが伸びる伸びる。
もうちょっと綺麗に書きたかったなあ。
同じ部屋の方がものすごく美しいコードを書いてて、関心すると同時にへこむ。
ループの終了条件をB以下にしないといけなかったのに、未満にしてしまってて落とされたorz
取れたものを凡ミスで落とすなんてどうしようもない・・・
載せたコードは練習部屋で直してシステムテストを通過したものです。
#include <iostream> using namespace std; class MinimalDifference { private: int sumDigit(int n) { int ret = 0; for(; n / 10 != 0;) { ret += n % 10; n /= 10; } return ret + n; } public: int findNumber(int A, int B, int C) { bool flag = false; int ans = 0; int buf1 = 0; int buf2 = 0; int buf3 = 0; int min = 1000000000; if(B == 1) return 1; buf1 = sumDigit(C); for(int i = A; i <= B ; i++) { buf2 = sumDigit(i); if(buf1 == buf2) { ans = i; flag = true; break; } else if(min > abs(buf2 - buf1)) { min = abs(buf2 - buf1); buf3 = i; } } if(!flag) ans = buf3; return ans; } };
500
複数行の文字列の中から、指定された文字列を得るには文字を何回交換すればいいかっていう問題。
横1列で成立させてもいいし縦複数行で成立させてもいいっていうのが厄介。
苦手な文字列操作系で軽く思考停止する。
縦で得るにはどうしたらいいか考えてたら時間終了した。
Cで息抜き
C++をC++らしく書けるようになるっていう課題もあるけど息抜きにCでゴルフ。
アルゴリズムを考えるだけなら言語は関係無いよね!
exit status
プログラム終了時のステータスを表示しろっていう問題。だと思う。
お得意の先頭の文字だけ見て判別する方法で決めうちする。それでも46B。
29Bって何やってるんだろう。乱数で運任せしたのかなあ。
main(i) { gets(&i); puts(i & 2 ? "1" : i & 1 ? "255" : "0"); }
show the way
道案内をしろっていう問題。最初問題の意味がよくわからなかった・・・
多分、最初の1行目に目的地に行くまでのチェックポイントの数、続く10行にスタート地点からの地図が渡される。
0からスタートして1、2〜と辿って行くのに上下左右どう進めばいいか表示しろ、ということでいいんだと思う。
これも決めうちしようかと思ったけど、真面目に解いてみようとやってみた。今のところ160B。
二次元配列を使うか迷ったけども、物は試しで一次元配列に挑戦。
一次元配列でも11離れた所(改行コードが入るから)に別の行の同じ列が来るので気をつければ解ける。
93Bは決めうちっぽいけど131Bは普通に解いてる予感。どちらも凄いなあ。
char m[112]; c, j; main(i) { read(0, m, 111); for(; j + 48 <= *m; i++) c ? m[i] == j + 48 ? puts(c - i > 0 ? c - i > 9 ? "top" : "left" : c - i < -9 ? "bottom" : "right"), c = i, i = 1, j++ : 0 : m[i] == 48 ? c = i, i = j = 1 : 0; }