コードを短くするのって楽しいですよね?(9)

続々、神の領域。


3進数について考えていこう。いま、末尾にTをつけた数字は3進数で表現された数値を意味するものとする。


たとえば、1111T=27+9+3+1 = 40である。また、bitはbinary digitの略であることから、ここでは3進数の1桁をtit(ternary digit)と書くことにする。


各titは、3^{n}を表現しているが、これは、3をn回掛け合わせたものであり、(素因数分解して2を含まないわけだから)明らかに奇数である。奇数に奇数を足すと偶数になる。よって、各titに1が増えると都度、偶奇が反転(逆転)する。たとえば、1Tは奇数であり、11Tは偶数、111T奇数、1111Tは偶数という具合である。また、10101010Tは、1があるtitが4つあるので偶数、という具合である。


また、2のtitは、偶奇には影響を及ぼさない。なぜなら、2のtitは2\cdot3^{n}を意味していて、これは2の倍数だから、これを加算しても元の数と偶奇は変わらないからである。例) 111Tは奇数。2111Tも奇数。212121Tも奇数。etc..


3で割ることは、titの右シフトに相当する。bit shiftならぬ、tit shiftである。また、最下位のtitをtit0と呼ぶことにする。


いま「n/=3」のようにtit shiftしていきながら、nが0になったときループを抜けることを考える。「各titに1が増えると都度、偶奇が逆転する」ことを思い出すと、各titに1が減るとき偶奇が反転するので、tit0が1の状態でtit shiftすると、偶奇が反転する。


例) 10101T:奇数 →(tit shift)→ 1010T:偶数


よって、偶奇はコントロールできる。たとえば、11111Tならば、右にtit shiftしていけば、奇数→偶数→奇数→偶数→奇数というように遷移するし、10101Tなら右tif shiftによって、奇数→偶数→偶数→奇数→奇数というように遷移する。


要するに、N回目右tit shift後に偶数にしたいなら、tit 0〜tit N(下から数えてN番目のtit)までの1であるtitの数も偶数にすることだ。(これは、tit Nを、決定するときに、その下位titであるtit 0〜tit N-1の1の数を考慮しながら決定していけば良い。)


かくして、


main(n){for(n=getchar()&1?'xxxx':120;n/=3;)puts(n&1?"no":"yes");}

という形が得られた。我々に残された課題は、この「xxxx」の部分を調整し、許容される文字コードにする作業だけだ。(つづく)