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

メモ

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

yukicoder No.103 素因数ゲーム リターンズ

問題はこちら
No.103 素因数ゲーム リターンズ - yukicoder

このゲームが本質的には山崩し(Nim)と同じであることはyukicoder No.2 素因数ゲーム - メモで説明した
前回との違いは、割れる回数が2回までになっていることのみ
よって(N言っちゃだめゲームと同様に考えて)各山はmod3で値を見れば良いことが分かる(厳密には、これが各山のgrundy数になっていることから分かる)

ということで前回のコードを流用して

int main(){
	int s,t,n,m,i;
	scanf("%d",&n);
	s=0;
	while(n--){
		scanf("%d",&m);
		for(i=2;i<=m;i++){
			for(t=0;m%i==0;){
				m/=i;
				t++;
			}
			s^=t%3;
		}
	}
	puts(s?"Alice":"Bob");
	return 0;
}

同じく前回のコードを流用することで

i,t,s;
main(m){
	for(gets(&i);~scanf("%d",&m);)for(i=2;m%i?s^=t%3,t=0,m>++i:(m/=i,++t););
	s=!puts(s?"Alice":"Bob");
}

ここまでは自明に短縮できる
あとは頑張ってループ圧縮

for(gets(&i);~scanf("%d",&m);)for(i=2;m%i?s^=t%3,t=0,m>++i:(m/=i,++t););
//↓形式的圧縮
for(gets(&i);m%i?s^=t%3,t=0,m>++i?:(i=2,~scanf("%d",&m)):(m/=i,++t););
//最初はi>48,m=1なので、「i=2,~scanf("%d",&m)」の部分が実行される
for(gets(&i);m%i?s^=t%3,t=0,++i>m?i=2,~scanf("%d",&m):1:(m/=i,++t););
//カッコを外す
for(gets(&i);m%i?s^=t%3,t=0,++i>m?i=-~scanf("%d",&m):1:(m/=i,++t););
//scanfの返り値を使う

ということで

i,t,s;
main(m){
	for(gets(&i);m%i?s^=t%3,t=0,++i>m?i=-~scanf("%d",&m):1:(m/=i,++t););
	s=!puts(s?"Alice":"Bob");
}

108B