kmjp's blog

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

yukicoder : No.2824 Lights Up! (Grid Edition)

ちょっと変わった問題設定。
https://yukicoder.me/problems/no/2824

問題

N*Nのグリッドがあり、各セルは0/1の値が設定されている。

  • セル(r,c)に対し行動をすると、(r,0),(r,c),(0,c)に対し以下の処理が行われる。
    • セル(r,c)に対し処理をすると、(r,c),((r-1)%N,c),(r,(c-1)%N),((r-1)%N,(c-1)%N)の4セルの01が反転する。

行動を繰り返し、全セルの値を0にできるか。できるなら行動の一例を示せ。

解法

1回の行動で0/1が変化するセルは、各列・各行偶数個なので、初期状態で1の個数は各列・各行で偶数でなければならない。
次に、セルの値の累積和を取ると、この行動は(r-1)行目と(c-1)列目を反転するのに相当する。
この処理を繰り返し、累積和も全部0になるように行動先のセルを選択しよう。

int N;
int A[1010][1010];
int R[1010],C[1010];
vector<pair<int,int>> V;

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N;
	FOR(y,N) {
		cin>>s;
		FOR(x,N) if(s[x]=='#') {
			A[y][x]=1;
			R[y]^=1;
			C[x]^=1;
		}
	}
	FOR(i,N) {
		if(R[i]||C[i]) {
			cout<<-1<<endl;
			return;
		}
		R[i]=C[i]=0;
	}
	
	if(N==1) {
		cout<<0<<endl;
		return;
	}
	N--;
	
	FOR(y,N) FOR(x,N) {
		if(y) A[y][x]^=A[y-1][x];
		if(x) A[y][x]^=A[y][x-1];
		if(y&&x) A[y][x]^=A[y-1][x-1];
		if(A[y][x]) R[y]^=1,C[x]^=1;
	}
	
	if(N%2) {
		FOR(i,N) if(R[0]!=R[i]||R[0]!=C[i]) break;
		if(i<N) {
			cout<<-1<<endl;
			return;
		}
	}
	
	FOR(y,N) FOR(x,N) if(A[y][x]^R[y]^C[x]) V.push_back({y,x});
	cout<<V.size()<<endl;
	FORR2(y,x,V) cout<<y+1<<" "<<x+1<<endl;
	
	
}

まとめ

これ難易度設定難しそう。★3.5でも良い気もするし…。