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() への第三引数としては、使われていないことに注意。