AOJ 1308 ICPC Asia resional 2010 Problem D: Awkward Lights

問題概要

nxmマスのパネルがある。
それぞれのパネルはONかOFFのいずれかである。


一つのパネルを押すと、そのパネルに加えてマンハッタン距離がちょうどdのパネルも全てON,OFFが反転する。
このとき、全てのパネルをOFFの状態にできるか答えよ。

制約条件

n,m≦25
d≦m+n

方針

スイッチ(k,l)がパネル(i,j)に影響をあたえるときa[(i,j)][(k,l)]=1,そうでないときa[(i,j)][(k,l)]=0という行列を考える。
a[(n,m)][(i,j)]=(i,j)の初期状態とする。


スイッチは二度押すと元に戻るので、mod 2でこの連立一次方程式を解き、解が存在すればいいかをみてやればよい。
連立一次方程式の解は掃きだし法により求めた。

ソースコード

const int dy[]={-1,0,1,0},dx[]={0,-1,0,1},dy2[]={1,-1,-1,1},dx2[]={1,1,-1,-1};
int m,n,d,s[25][25];
int main()
{
	while(scanf("%d%d%d",&n,&m,&d),m){
		int N=m*n;
		vector<vi> a(N,vi(N+1,0));
		rep(i,m)rep(j,n)scanf("%d",s[i]+j), a[i*n+j][N]=s[i][j];
		rep(i,N)(a[i][i]+=1)%=2;
		rep(i,m)rep(j,n)rep(dir,4)rep(k,d){
			int y=i+dy[dir]*d+dy2[dir]*k, x=j+dx[dir]*d+dx2[dir]*k;
			if(0<=y&&y<m&&0<=x&&x<n){
				(a[y*n+x][i*n+j]+=1)%=2;
			}
		}
		int j=0;
		rep(i,N){
			int mi=i;
			if(!a[mi][j])for(int k=i+1;k<N;k++)if(a[mi]<a[k]){
				mi=k;
				if(a[mi][j])break;
			}
			swap(a[i],a[mi]);
			for(;j<N&&a[i][j]==0;j++);
			if(j>=N)break;
			assert(a[i][j]);
			rep(k,N)if(i<k&&a[k][j])for(int l=j;l<=N;l++)(a[k][l]+=a[i][l])%=2;
			j++;
		}
		bool ok=1; j=0;
		rep(i,N)if(ok&&a[i][N]){
			for(;j<N&&a[i][j]==0;j++);
			if(j>=N)ok=0;
		}
		printf("%d\n",(int)ok);
	}
	return 0;
}