Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

品質管理

会津タカダ市が生産販売する布製コースターは、対称なデザインでとても美しいことで知られている。会津タカダ市では品質管理の一環として、製造ラインにカメラを設置し、各コースターを撮影して得られた画像が対称になっているかを自動で検証している。各コースターは N × N ピクセルの正方形の白黒画像として表される。各ピクセルは白または黒の画像に対応して、0 または 1 の値をとる。

この度、生産ラインの機器更新にともなって、画像解析システムのソフトウェアを更新することになった。新システムでは、通信データ量を削減する工夫がなされ、以下の方法でカメラから解析システムにデータが送られてくる。

ラインに流れてくる最初のコースターの情報は、N × N ピクセルの画像としてシステムに送られてくる。

２枚目以降のコースターの情報は、１つ前に送られた画像との差分だけが送られてくる。差分は、「0 から 1 」または「1 から 0 」へと変化したピクセルの位置の集合として与えられる。

C 枚のコースターについて、１枚目の画像のピクセル情報と続く C - 1 枚分の差分情報を入力し、上下対称かつ左右対称となっているコースターの枚数を報告するプログラムを作成せよ。

Input

入力は以下の形式で与えられる。

C N
p11p12...p1N
p21p22...p2N
:
pN1pN2...pNN
diff1
diff2
:
diffC−1

１行目にコースターの枚数 C (1 ≤ C ≤ 10000) と画像の縦と横のピクセル数 N (2 ≤ N ≤ 1000 かつ N は偶数) が与えられる。２行目から N + 1 行目に最初のコースターの画像のピクセルを表す N行 × N 列の数字 pij (pij は 0 または 1)が与えられる。

N + 2 行目以降に、２枚目以降のコースターの情報を表す差分 diffi が次の形式で与えられる。

D
r1 c1
r2 c2
:
rD cD

１行目に変化したピクセルの数 D (0 ≤ D ≤ 100) が与えられる。続くD 行に変化したピクセルの行と列の番号をそれぞれ表す ri とci (1 ≤ ri, ci ≤ N) が与えられる。diffi の中に、同じ位置は２回以上与えられない。

Output

上下対称かつ左右対称となっているコースターの枚数を１行に出力する。

Sample Input 1

7 8
00100000
00011000
10111101
01100110
01000110
10111101
00011000
00100100
2
5 3
1 6
1
6 8
3
6 8
3 3
3 6
2
6 3
6 6
0
2
3 8
6 8

Sample Output 1

3

入力例１のコースターの画像を以下に示す。この場合、２枚目、５枚目、６枚目のコースターが上下対称かつ左右対称となるため、3と報告する。

Sample Input 2

1 6
000000
000000
010010
010010
000000
000000

Sample Output 2

1

Sample Input 3

2 2
00
00
4
1 1
1 2
2 1
2 2

Sample Output 3

2

Solution in C++ (judge verdict: Accepted)

// 2017/08/01 Tazoe

#include <iostream>
using namespace std;

bool check(bool P[1000][1000], int N)
{
	for(int y=0; y<N/2; y++){
		for(int x=0; x<N/2; x++){
			if(P[y][x]==P[y][N-1-x]
			&& P[y][x]==P[N-1-y][x]
			&& P[y][x]==P[N-1-y][N-1-x])
				continue;

			return false;
		}
	}

	return true;
}


int main()
{
	int C, N;
	cin >> C >> N;

	bool P[1000][1000];
	for(int y=0; y<N; y++){
		for(int x=0; x<N; x++){
			char p;
			cin >> p;

			P[y][x] = (bool)(p-'0');
		}
	}
/*
	for(int y=0; y<N; y++){
		for(int x=0; x<N; x++){
			cout << (int)P[y][x];
		}
		cout << endl;
	}
*/

	bool Q[1000][1000];
	int  sumQ = 0;
	for(int y=0; y<N/2; y++){
		for(int x=0; x<N/2; x++){
			Q[y][x]         = !(P[y][x]==P[y][x]);
			Q[y][N-1-x]     = !(P[y][N-1-x]==P[y][x]);
			Q[N-1-y][x]     = !(P[N-1-y][x]==P[y][x]);
			Q[N-1-y][N-1-x] = !(P[N-1-y][N-1-x]==P[y][x]);
			if(Q[y][x])          sumQ++;
			if(Q[y][N-1-x])      sumQ++;
			if(Q[N-1-y][x])      sumQ++;
			if(Q[N-1-y][N-1-x])  sumQ++;
		}
	}

//	cout << sumQ << endl;

	int cnt = 0;

	if(sumQ==0){
		cnt++;
	}

	for(int i=1; i<C; i++){
		int D;
		cin >> D;

		for(int j=0; j<D; j++){
			int r, c;
			cin >> r >> c;

			if(r<=N/2 && c<=N/2){
				Q[r-1][N-c] = !Q[r-1][N-c];
				Q[N-r][c-1] = !Q[N-r][c-1];
				Q[N-r][N-c] = !Q[N-r][N-c];
				if(Q[r-1][N-c])  sumQ++;  else  sumQ--;
				if(Q[N-r][c-1])  sumQ++;  else  sumQ--;
				if(Q[N-r][N-c])  sumQ++;  else  sumQ--;
			}
			else{
				Q[r-1][c-1] = !Q[r-1][c-1];
				if(Q[r-1][c-1])  sumQ++;  else  sumQ--;
			}
		}

		if(sumQ==0){
			cnt++;
		}
	}

	cout << cnt << endl;

	return 0;
}