メモ

yukicoderでゆるふわgolf

yukicoder No.441 和か積

問題はこちら
No.441 和か積 - yukicoder

場合分けをすれば簡単に分かる。
必要ならAとBを入れ替えることでA≦Bと仮定して良い
・Aが0のとき
 Bも0なら'E'、さもなくば'S'
・Aが1のとき
 必ず'S'
・Aが2のとき
 Bも2なら'E'、さもなくば'P'
・Aが3以上のとき
 必ず'P'

Cでは200桁の整数を受け取るのは難しい。
上の場合分けを見ると、AもBも「3以上」はまとめて扱って良いことに気づく。
つまり、値が3以上ならそれを3に置き換えても結果に影響しない。
(上のように厳密に場合分けしなくても、例えば「値が10000以上なら10000に置き換えても和と積の大小関係は変わらなくない?」というのはイメージできると思う)

ということで、次のようにできる

int main(){
	char s[300];
	int a,b;
	scanf("%s",s);
	a=strlen(s)>1?9:atoi(s);//2桁なら9にしてしまう
	scanf("%s",s);
	b=strlen(s)>1?9:atoi(s);//同上
	if(a*b==a+b)putchar('E');
	else if(a*b>a+b)putchar('P');
	else putchar('S');
	return 0;
}

この方針のまま縮めるとこう

char s[999];
a;
main(b){
	scanf("%s ",s);
	a=strlen(s)>1?9:*s-48;
	b=strlen(gets(s))>1?9:*s-48;
	a=!putchar(a*b-a-b?a*b<a+b?83:80:69);
}

でもstrlenは長いし、getcharかreadでいい感じにやりたい
とりあえずぱっと思いつく簡単なやつ

#define f(x)for(;(t=getchar())>32;x=x?9:t-48);
//a,bは最初は0。先頭の桁を保存した後、もし2桁目以降があれば9に書き換える
a,b;
main(t){
	f(a);
	f(b);
	a=!putchar(a*b-a-b?a*b<a+b?83:80:69);
}

これをぐっと睨んでdefineをどうにかすると

t,a,b;
main(i){
	for(;read(0,&t,1);t>32?b=b?9:t-48:i--?a=b,b=0:0);
	a=!putchar(a*b-a-b?a*b<a+b?83:80:69);
}

このようになる。
ところで最後の条件式はa*b-a-b=(a-1)*(b-1)-1であることから、a,bに実際の数より1小さな値が入るように予め調整しておけば次のように短くできる

putchar(a*b-a-b?a*b<a+b?83:80:69);
putchar(a*b-1?a*b<1?83:80:69);

さらに、readをfor文の終了条件にしていると、returnがいい感じになるような気がしたので、最後の代入も省略して

t,a,b;main(i){for(;read(0,&t,1);t>32?b=b?9:t-49:i--?a=b,b=0:putchar(a*b-1?a*b<1?83:80:69));}

92B

2018/01/24追記
よくみるとこれは嘘解法。
例えば「12 2」などで落ちる。
修正してもよいが、じつは愚直解のほうがよほど短くなる。

double a,b;
main(){
	scanf("%lf%lf",&a,&b);
	putchar(a-b||(a&&a-2)?a*b>a+b?80:83:69);
}

81B
これが上手く動作することの証明には、丸め誤差の取扱などに熟知している必要がある。面倒くさいのでここでは省略するが、このプログラムは常に正しい値を返す。
しかし、一見同じ動作をするようにみえる次のコードはそうではない。

double a,b;
main(){
	scanf("%lf%lf",&a,&b);
	putchar(a-b||(a&&a-2)?a*b<a+b?83:80:69);
}

aが十分大きな値であり、b=1のとき、a+bは情報落ちによりaとなってしまう。