kmjp's blog

競技プログラミング参加記です

yukicoder : No.1016 三目並べ

こういうのパッと思いつけないんだよな。
https://yukicoder.me/problems/no/1016

問題

1xNの碁盤で三目並べを行う。
現在の碁盤の状態が与えられる。

この三目並べは3つ自分の色の碁石を並べると勝ちではなく、後手は先手が3つ並べるのを防ぐと勝ちとなる。
現在の状態から初めて、勝者はどちらか。

解法

先手が3つ並べることができるかどうかを判定しよう。
まず、初期状態で碁盤の以下の構成を持つと、後手は先手を阻止できない。

ooo
oo-
  • oo
  • o--
    • o-

それ以外を考える。
o-------o
のように、先手の石の間に空白が奇数個あると先手の勝ちである。
石から偶数個の位置を順に埋めて行くと、最後先手の手番でo-oを埋める状態になる。
それ以外を個別に見ていくと後手必勝。

int T;
int N;
string S;

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>T;
	while(T--) {
		cin>>N>>S;
		int win=0;
		FOR(i,N-2) if(S.substr(i,3)=="ooo") win=1;
		FOR(i,N-2) if(S.substr(i,3)=="oo-") win=1;
		FOR(i,N-2) if(S.substr(i,3)=="-oo") win=1;
		FOR(i,N-3) if(S.substr(i,4)=="-o--") win=1;
		FOR(i,N-3) if(S.substr(i,4)=="--o-") win=1;
		int pre=-1;
		FOR(i,N) {
			if(S[i]=='x') pre=-1;
			if(S[i]=='o') {
				if(pre>=0 && (i-pre)%2==0) win=1;
				pre=i;
			}
		}
		if(win) cout<<"O"<<endl;
		else cout<<"X"<<endl;
	}
}

まとめ

こういうの一発で通る気しないんだよな。