問題はこちら
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