読者です 読者をやめる 読者になる 読者になる

メモ

yukicoderで遊んでいる競プロゆるふわ勢

yukicoder No.161 制限ジャンケン

問題はこちら
No.161 制限ジャンケン - yukicoder

相手が出す手がわかっているので順序は関係ない

可能な限り勝てるような手を出せば良い

#define min(a,b)(a<b?a:b)
int main(){
	int a[3]={},b[3]={},s,i,t;
	scanf("%d%d%d\n",a,a+1,a+2);
	for(;t=~getchar();){
		if(~t=='G')b[0]++;
		else if(~t=='C')b[1]++;
		else if(~t=='P')b[2]++;
	}
	s=0;
	//勝てる手を出す
	for(i=0;i<3;i++){
		t=min(a[i],b[(i+1)%3]);
		a[i]-=t;
		b[(i+1)%3]-=t;
		s+=t*3;
	}
	//残りは引き分け
	for(i=0;i<3;i++)s+=min(a[i],b[i]);
	printf("%d",s);
	return 0;
}

まずは読み込み部分
'G'が71、'C'が67、'P'が80なのでgetchar()/7で10,9,11にすることができる。このとき改行は1でEOFは0
勝てる手をだす処理も、読み込みが終わってからではなく随時実行することにすればループを1つ減らせる
(引き分け処理は勝てる手を全て出し終わった後でなければならない)
ということでこうまとめられる

for(scanf("%d%d%d",a+1,a,a+2);t=getchar()/7;)t-1?a[i=(t+1)%3]?a[i]--,s+=3:b[t%3]++:0;
//この部分だけならt-1?a[i=(t+1)%3]--?s+=3:b[t%3]++:0;でもいいが
//引き分け処理が面倒になるのでaには0未満の値が入らないようにしておく

最後にループ圧縮をして

for(scanf("%d%d%d",a+1,a,a+2);t=getchar()/7;)t-1?a[i=(t+1)%3]?a[i]--,s+=3:b[t%3]++:0;for(i=0;i<3;i++)s+=a[i]<b[i]?a[i]:b[i];
//iの初期化の都合でt-1の分岐をやめてみる(こうすると最後に改行を読み込んだ時にi=2が代入される)
//b[-8]にアクセスしているが偶然うまくいく
for(scanf("%d%d%d",a+1,a,a+2);(t=getchar()/7)?a[i=(t+1)%3]&&t-1?a[i]--,s+=3:++b[t-9]:(s+=a[i]<b[i]?a[i]:b[i],i--););
for(scanf("%d%d%d",a+1,a,a+2);!(t=getchar()/7)?s+=a[i]<b[i]?a[i]:b[i],i--:a[i=(t+1)%3]&&t-1?a[i]--,s+=3:++b[t-9];);

ということでまとめると

a[9],b[9],s,i;
main(t){
	for(scanf("%d%d%d",a+1,a,a+2);!(t=getchar()/7)?s+=a[i]<b[i]?a[i]:b[i],i--:a[i=(t+1)%3]&&t-1?a[i]--,s+=3:++b[t-9];);
	s!=printf("%d",s);
}

156B

2016/05/18追記
&&を*に書き換えられる箇所があったので1B短縮

a[9],b[9],s,i;
main(t){
	for(scanf("%d%d%d",a+1,a,a+2);!(t=getchar()/7)?s+=a[i]<b[i]?a[i]:b[i],i--:a[i=(t+1)%3]*~-t?a[i]--,s+=3:++b[t-9];);
	s=!printf("%d",s);
}

155B

16/06/06追記
fminの存在を忘れていた

a[9],b[9],s,i;
main(t){
	for(scanf("%d%d%d",a+1,a,a+2);!(t=getchar()/7)?s+=fmin(a[i],b[i]),i--:a[i=(t+1)%3]*~-t?a[i]--,s+=3:++b[t-9];);
	s=!printf("%d",s);
}

151B