Rolling division
Rolling division。C のための問題という感じだった。トップ nai さん 74B、2位 inaniwa さん 75B と3位の私の 76B 解。
74B: main(i){for(i=-gets(&i)%3+2*atoi();i-1;i=i/2+i%4/3)printf("%.1f\n",i*.5);} 75B: main(a){for(a=4*atoi(gets(&a))+a%3;a-2;printf("%.1f\n",a/2.))a=a+a%4/3>>1;} 76B: main(a){for(scanf("%d",&a),a+=a+a%2;a-1;a=a+a%4/3>>1)printf("%.1f\n",a/2.);}
違いは、入力の処理と、除算+まるめ処理。特に、後者による 1B 差:
i=i/2+i%4/3 a=a+a%4/3>>1
nai さんさすがだ。4 の剰余系で考えると以下のよう。
i%4 i/2 i%4/3 i/2+i%4/3 0 0 0 0 1 0 0 0 2 1 0 1 3 1 1 2
この手の、整数除算のマジックは過去問でもあったな。なかなか思いつくのが難しい。
終了・公開後、inaniwa さんにより、not さんの解を基にした 71B が出た。
n;m;main(){for(scanf("%d.%d\n",&n,&m);n;m=m?!++n:n%2*5,n/=2)vprintf();}
こちらは、vprintf() が見事に効を奏している。ところで、この vprintf() の引数構造だが、その物理的構造は実装依存だ。ポータブルな実装は、va_arg マクロを使って実装するが、あなごるサーバーの実装は、以下の構造をしている。
main(){ int a[4]={10,20,30,40}; vprintf("%d:%d:%d:%d\n",a); // ==> 10:20:30:40 } 〜〜〜〜〜 void g(x){ vprintf("%d:%d:%d:%d\n",&x); // ==> 11:22:33:44 } main(){ g(11,22,33,44); }
上記、inaniwa(not) さん 71B 解で言うと、scanf() の第三引数、&m は、vprintf() への第三引数としては、使われていないことに注意。