カメヲラボ

主にプログラミングとお勉強全般について書いてます

Parliament(5)

  • 超絶テクニック(短縮その1)

前回書いたコードをさらりと短縮すると、

i,m=2;
main(t){
  for(scanf("%d",&t);t-m>=0;)t-=m++;
  for(m-=2;i<m;++i)
    printf("%d ",i+2+t/m+(i+t%m>=m));
}

このように100B程度にはすんなり出来る。

このコードを見て気になる部分は、


①mの初期値をわざわざ2にしているにもかかわらずあとで2を引いている。
②不等号は出来れば'='を使いたくない。
③for文は一回で出来ないだろうか。
という点だ。

実は①が最も重要で難しいポイントで、「最初に2を引きたい!」と思うと、ついついmainの第一引数が1であることを利用して

i,t;
main(m){
  for(scanf(...);t-m>=0;t-=++m);
  ...
}

と書きたくなる。しかしこうしてしまうとループを抜けた後、mを1減らさねばならない。無意味なデクリメント--mは3バイトも消費する。
よって、mの初期値を1にするのはよろしくない。ここでは以下のようなテクニックを使う。

正の整数について、ビット反転を行うと、


~1 = -2
~2 = -3
~3 = -4
.
.
.
のように絶対値が1大きくなる。つまり、

i,m;
main(t){
  for(scanf(...);t-m>=0;t+=~++m);
  ...
}

と書けば、~の1バイト消費で--mと書く必要がなくなるので2バイトの節約だ。

ただし、終了判定の部分

t-m>=0

には~をつけないので0以上のままでは良くない。
というわけで

t-m>=2

としておく。こうすれば、さらに

t-m>1

と書くことが出来て1バイトお得である。