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大きくなる。つまり、
~1 = -2
~2 = -3
~3 = -4
.
.
.
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バイトお得である。