メモ

yukicoderでゆるふわgolf

yukicoder No.637 X: Yet Another FizzBuzz Problem

問題はこちら
No.637 X: Yet Another FizzBuzz Problem - yukicoder

FizzBuzzは8文字、FizzとBuzzは4文字、それ以外のときは100以上なら3文字、そうでなく10以上なら2文字、さもなくば1文字

main(){
	int ans=0;
	for(int i=0;i<5;i++){
		int n;
		scanf("%d",&n);
		if(n%15==0)ans+=8;
		else if(n%3==0||n%5==0)ans+=4;
		else if(n>=100)ans+=3;
		else if(n>=10)ans+=2;
		else ans++;
	}
	printf("%d",ans);
}

桁数が欲しいときはlog10を使う。また、3の倍数5の倍数のときに独立に4増えると考えて、次のようにまとめる事ができる

s;
main(n){
	for(;~scanf("%d",&n);)s+=!(n%3)+!(n%5)<<2?:log10(n)+1;
	printf("%d",s);
}

80B

yukicoder No.593 4進FizzBuzz

問題はこちら
No.593 4進FizzBuzz - yukicoder

頭の桁から順に見て、4倍しながら足していくことで求める事ができる

char s[1000010];
main(){
	gets(s);
	int n=strlen(s);
	int m3=0,m5=0;
	for(int i=0;i<n;i++){
		m3=(m3*4+s[i]-'0')%3;
		m5=(m5*4+s[i]-'0')%5;
	}
	if(m3==0){
		if(m5==0)puts("FizzBuzz");
		else puts("Fizz");
	}else{
		if(m5==0)puts("Buzz");
		else puts(s);
	}
}

FizzBuzzゴルフは難しすぎてよくわからないので適当に

i,n;
char s[1<<21];
main(){
	for(gets(s);s[i];n=(n*4+s[i++]-3)%15);
	puts(n%5?n%3?s:"Fizz":"FizzBuzz"+n*n%3*4);
}

106B

yukicoder No.597 concat

問題はこちら
No.597 concat - yukicoder

言われたとおりやるだけ
実際に繋げなくても、入力をそのま順番に出力していけば繋がる

main(){
	int n;
	char s[99];

	scanf("%d",&n);
	while(n--){
		scanf("%s",s);
		printf("%s",s);
	}
}

1行目の読み飛ばしをどうするかが問題

a[];main(){for(gets(a);gets(a);printf("%s",a));}
//↑50B ↓49B
a[];main(i){for(;gets(a);printf("%s",a+!--i));}

49B

yukicoder No.591 (^o^)/

問題はこちら
No.591 (^o^)/ - yukicoder

言われたとおりにやるだけ

main(){
	char a,b;
	scanf("%c %c",&a,&b);//"%c%c"だと2文字目が得られない(改行の読み飛ばし)
	printf("(%c%c%c)/",a,b,a);
}

読み込みを次のようにまとめることが出来る

a;
main(){
	gets(gets(&a)+1);
	printf("(%s%c)/",&a,a);
}

50B
aをメインの引数にするとセグフォになる。ぐぬぬ
一応解説。
&aはint*型だが、getsの引数に与えて暗黙にchar*に変換され、入力の1文字がaの下位8bitに入る。ここまではよくやる。
ここでgetsの返り値はchar*なので(実際にはincludeを省略しているのでint!)、+1することにより、aの次の8bitを指すアドレスを得る事ができる。
よって、例えばサンプル1が入力として与えられた場合、gets(gets(&a)+1)が終わった時点でa='^'+'o'*256となっている。
つまり(char*)&aは"^o\0"となっているので、最初の2文字はまとめて出力することができる。
更に、%cで出力する際にint型の変数を渡すと下位8bitのみが使われるので、3文字目もそのまま出力することができる。

yukicoder No.627 ランダムウォークの軌跡

問題はこちら
No.627 ランダムウォークの軌跡 - yukicoder

言われたとおりにやる。
X[0]=0とするとT=1における場合分けをしなくて良くなるので楽

int x[999],t;
main(){
	scanf("%d",&t);
	for(int i=1;i<=t;i++)scanf("%d",x+i);
	for(int i=1;i<=t;i++)if(abs(x[i-1]-x[i])!=1){
		puts("F");
		return 0;
	}
	puts("T");
}

縮める。
直前の値をa、今の値をbとして値の受け渡しをいい感じにする。

a,b,s;
main(i){
	for(;~scanf("%d",&b);)--i?s|=abs(a-b)-1,a=b:0;
	putchar(s?70:84);
}

78B

2018/01/22追記
実はもう1つ考えていた方針があった。
(a,b)→(b,*)と変換する必要があるわけだが、(b,a-b)にすることができれば、absに食わせる引数との兼ね合いで上手く縮むのではないか

//(a,b)→(b,b-a)と変換
s,a,b;main(i){for(;~scanf("%d",&b);)s|=--i&&abs((b-=a,a+=b,b))-1;putchar(s?70:84);}
//関数の引数は後ろから評価されるという処理系依存テクにより括弧を省略
s,a,b;main(i){for(;~scanf("%d",&b);)s|=--i&&abs(b,a+=b,b-=a)-1;putchar(s?70:84);}
//さらに未定義動作で縮める
s,a,b;main(i){for(;~scanf("%d",&b);s|=--i&&abs(b,a+=b-=a)-1);putchar(s?70:84);}

これ自体は79Bだが、「ワイド文字列リテラル」というものと組み合わせることで短縮ができる。
ワイド文字列とは文字列の亜種のようなもので、1文字を2Bまたは4Bで表す型(らしい)。L"string"というように、頭にLをつけて記述する。
実態としては(char*)L"XYZ"は"X\0\0\0Y\0\0\0Z\0\0\0"と等しいので、次のように短縮できる

s,a,b;main(i){for(;~scanf("%d",&b);s|=--i&&abs(b,a+=b-=a)-1);putchar(s?70:84);}
s,a,b;main(i){for(;~scanf("%d",&b);s|=--i&&abs(b,a+=b-=a)-1);puts(L"TF"+s);}

76B