メモ

yukicoderでゆるふわgolf

yukicoder No.564 背の順

問題はこちら
No.564 背の順 - yukicoder

最初は1位で、高い人が現れるたびに順位は1つ下がる

h,n,t,S;
main(){
	scanf("%d%d",&h,&n);
	S=1;
	for(int i=1;i<n;i++){
		scanf("%d",&t);
		if(t>h)S++;
	}
	printf("%d",S);
	if(S%10==1)puts("st");
	else if(S%10==2)puts("nd");
	else if(S%10==3)puts("rd");
	else puts("th");
}

最初の順位を0位にしておけば最初の処理がまとめられる
また、文字の出力部分は適当なフォーマット指定により短くできる(はじめて知った)

h,t,s;
main(i){
	for(;~scanf("%d",&t);){
		if(!h)h=t;
		if(i--)s+=t>=h;//nだけ読み飛ばし
	}
	printf("%d%.2s",s,"thstndrd"+(s%10<4)*s%10*2);
}
h,t,s;
main(i){
	for(;~scanf("%d",&t);s+=i--&&t/h)h=h?:t;
	printf("%d%.2s",s,"thstndrd"+(s%10<4)*s%10*2);
}

101B

yukicoder No.549 素材合成システム

問題はこちら
No.549 素材合成システム - yukicoder

合成素材の側の経験値の最終的な寄与度は高々floor(a/2)
実際に、一番経験値が高い奴をベースにし、残りを素材として順次合成していくことで最大になる。

c(int*a,int*b){return*b-*a;}

a[100010],n,S;
main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++)scanf("%d",a+i);
	qsort(a,n,4,c);
	S=a[0];
	for(int i=1;i<n;i++)S+=a[i]/2;
	printf("%d",S);
}

ソートしなくても、最大値を記憶しておくことで先頭から順に読み込むことができる

#define max(p,q)(p>q?p:q)
t,n,M,S;
main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&t);
		M=max(M,t);
		S+=t/2;
	}
	printf("%d",S-M/2+M);
}

式を変形して最後の出力をS-~M/2にできる
ぎゅっとする

s,x,m;
main(i){
	for(;~scanf("%d",&x);)--i?m<x?m=x:0,s+=x/2:0;
	printf("%d",s-~m/2);
}

80B

yukicoder No.561 東京と京都

問題はこちら
No.561 東京と京都 - yukicoder

DPやるだけ(といいつつ、後ろから見る方法しか思いつかなかったので要反省)

(i-1)日目が終了した時点で東京にいるときの最大利益をT、京都にいるときの最大利益をKとおく。
i日目に東京でt、京都でk得られる場合
i日目が終了した時点で東京にいるときの最大利益はmax(T,K-d)+t、京都にいるときの最大利益はmax(K,T-d)+kとなる。
これによりK,Tを順次更新していけば良い。
初期値はT=0、K=-dとなる。(1日目が始まる前に京都へ移動したと考える)

T,K,t,k,n,d;
main(){
	scanf("%d%d",&n,&d);
	K=-d;
	for(int i=0;i<n;i++){
		scanf("%d%d",&t,&k);
		t=fmax(T,K-d)+t;
		k=fmax(K,T-d)+k;
		T=t;
		K=k;
	}
	printf("%d",T>K?T:K);
}

数値は2個1セットで読み込めるので次のようにできる

T,K,t,k,d;
main(i){
	for(;~scanf("%d%d",&t,&k);){
		if(--i){
			t=fmax(T,K-d)+t;
			k=fmax(K,T-d)+k;
			T=t;
			K=k;
		}else{
			d=k;
			K=-d;
		}
	}
	printf("%d",T>K?T:K);
}

これをぎゅっとする

T,K,t,k,d;
main(i){
	for(;~scanf("%d%d",&t,&k);)K=--i?k+=fmax(K,T+d),T=t+fmax(T,K+d),k:(d=-k);
	printf("%d",T>K?T:K);
}

yukicoder No.537 ユーザーID

問題はこちら
No.537 ユーザーID - yukicoder

2つの数A,Bを連結するのは、文字列として処理するのでも良いが、Cだと面倒なので計算をする
数Bの桁数は\lfloor \log_{10} B \rfloor +1で得られるので、AとBをこの順で連結したものはA*10^{\lfloor \log_{10} B \rfloor +1}+Bで求められる

Nが大きいので1~√Nまでを調べる

long n,s[20000],k,i,t,A;
c(long*a,long*b){return *a<*b?1:*a>*b?-1:0;}
main(){
	scanf("%ld",&n);
	for(i=1;i*i<=n;i++)if(n%i==0){
		s[k++]=n/i*pow(10,t=log10(i)+1)+i;
		s[k++]=i*pow(10,t=log10(n/i)+1)+n/i;
	}
	qsort(s,k,8,c);
	for(;k--;)A+=s[k]!=s[k+1];
	printf("%d",A);
}

OEISによれば10^12以下の数は高々6720個の約数しか持たないので、「既出の数かどうか」は毎回チェックしても間に合う
また、iがnの約数なら、「iをn/iと取り替える」という操作を2度行うとiはもとの値に戻るので、これを利用して、前後の入れ替えを1つにまとめられる

long n,s[9999],k,i,j,t,x;
main(){
	scanf("%ld",&n);
	for(i=1;i*i<=n;i++)if(n%i==0){
		for(x=0;x<2;x++){
			t=n/i*pow(10,t=log10(i)+1)+i;
			for(j=0;j<k;j++)if(s[j]==t)break;
			if(j==k)s[k++]=t;
			i=n/i;
		}
	}
	printf("%d",k);
}

3重for文をいい感じにまとめる。
特に工夫せずとりあえず縮める

for(scanf("%ld",&n);i*i++<n;)
	for(;n%i?0:++x%3;j==k?s[k++]=t:0,i=n/i)
		for(t=n/i*pow(10,t=log10(i)+1)+i,j=0;j<k&&s[j++]-t;);

s[]への代入の部分もループの中にまとめたほうが短くなる

for(t=n/i*pow(10,t=log10(i)+1)+i,j=0;j<k?s[j++]-t:!(s[k++]=t););
for(t=n/i*pow(10,t=log10(i)+1)+i,j=k;j?s[--j]-t:!(s[k++]=t););

ということでできたのがこれ

long n,s[9999],i,x,k,t;
main(j){
	for(scanf("%ld",&n);i*i++<n;)
		for(;n%i?0:x++%3;i=n/i)
			for(t=n/i*pow(10,t=log10(i)+1)+i,j=k;j?s[--j]-t:!(s[k++]=t););
	printf("%d",k);
}

161B

yukicoder No.560 ふしぎなナップサック

問題はこちら
No.560 ふしぎなナップサック - yukicoder

算数やるだけ
ナップサックの中にM円入っているとき、1回叩いた後は (2M+(M+1)+0)*1/3=M+1/3 より(M+1/3)円になる。
これはMに依らないのでこの操作をN回行うとM+N/3円になる。
写像f(M)=M+1/3をN回適用した)

main(m,n){
	scanf("%d%d",&m,&n);
	printf("%.9f",m+n/3.);
}

53B