メモ

yukicoderでゆるふわgolf

yukicoder No.405 ローマ数字の腕時計

問題はこちら
No.405 ローマ数字の腕時計 - yukicoder


負の数の剰余にだけ注意すれば良い

char a[][5]={"I","II","III","IIII","V","VI","VII","VIII","IX","X","XI","XII"},b[];
i;
main(x){
	for(scanf("%s%d",b,&x);strcmp(b,a[i++]););
	i=!puts(a[(x+i+1199)%12]);
}

思考停止で作ったこれが162Bだからコレよりは短くできないとお話にならない

ということでこんな方針で
入力:ローマ数字を数に変換してsに保存
'I'が来たらs+=1
'V'が来たらs+=5
'X'が来たら、sが0のときはs+=10、そうでないときはs+=8
出力:出力すべき数をsに保存
s=0なら終わり
s=9なら"IX"を出力して終わり
s≧10なら'X'を出力してs-=10
s≧5なら'V'を出力してs-=5
さもなくば'I'を出力してs-=1

最下位bitをみれば'I'と'V''X'は区別でき、下から2つめのbitを見れば'V'と'X'は区別できる

s;
main(x){
	for(;!scanf("%d",&x);s+=x&1?:x&2?5:s?8:10)x=getchar();
	for(s=(s+x+1199)%12;s-8?~s:!puts("IX");putchar(s>8?s-=10,88:s-->3?s-=4,86:73));
	//上記説明とはsが1ずれている事に注意
}

144B


2017/07/29追記
出力を工夫する。write関数を使えば、例えばwrite(1,"VIIIIXII"+A,B)という形でかけそう
以下sは0~11とする(0のとき"I"、…11のとき"XII")
・Bについて
これは、文字列の長さなので

s B
0,1,2,3 s+1
4,5,6,7 s-3
8 2
9,10,11 s-8

となる。ぐっと睨むとこれは次のように書ける
s-8?s+1-s/4*4-s/8:2
s+1-s/4*4-s/8はsが8のとき0になるので、さらに次のように書き換えられる
s+1-s/4*4-s/8?:2
・Aについて

s A
0,1,2,3 1
4,5,6,7 0
8 4
9,10,11 5

s-8?1-s/4+s/8*6:4

ということで次のようにまとめられる

write(1,"VIIIIXII"+(s-8?1-s/4+s/8*6:4),s+1-s/4*4-s/8?:2);

……といいたいところだが、文字列の部分を"VIIIIXII"から"IIIIVIIIXII"に変えることでAの部分を短くできる
・A再考

s A
0,1,2,3 0
4,5,6,7 4
8 7
9,10,11 8

s-8?s/4*4:4
s-8?s&-4:4

ということで、まとめると次のようになる

s;
main(x){
	for(;!scanf("%d",&x);s+=x&1?:x&2?5:s?8:10)x=getchar();
	s=(s+x+1199)%12;
	write(1,"IIIIVIIIXII"+(s-8?s&-4:7),s+1-s/4*4-s/8?:2);
}

134B