Find The Operations
Let’s try to modify a 0-1 grid. Problem statement here.
Difficulty Level
Medium-Hard
Required Knowledge
Gaussian Elimination, Linear Algebra
Time Complexity
O(N^2) for each test case
Problem Setter
Tran Dang Tuan Anh
Problem Tester
Peng Cao
Approach
Given N and D
and initial matrix given is M[N][N].
Construct Matrices A[NXN][NXN] and B[NXN]. Such as
For all A [i][j] i be the index for each value in M, and A[i][j] = 1 if j lies in the given “D” Manhattan distance from i.
Hence we get the A[][] matrix that contains the information of all the j values that will be flipped, for corresponding i.
And we fill B[i] with initial values of all i in M[N][N]
Now we know that each element will be flipped only once. It can have a value 0 or 1 initially. So we try to solve by Gaussian Elimination equation Ax=B but instead of subtraction we take ^(XOR) as we don’t have to deal with -ve values.
If B[i] ==1 and corresponding all the j’s in A[i][j] are 0. It is Impossible to solve.
Also when B[i]== 1 and diagonal A[i][i] =0 we can not flip the value hence Impossible to solve.
For all other cases it is Possible and in the end we are left with a diagonal matrix and the result matrix B. Corresponding to the state where all Elements are 0.
After that we simply count the elements in B[NXN] array and for each index in B (index/N, index%N) is the required index.
Setter’s Code :
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <memory.h>
#include <sstream>
#include <complex>
#include <cassert>
#define REP(i,n) for(int i = 0, _n = (n); i < _n; i++)
#define REPD(i,n) for(int i = (n) - 1; i >= 0; i--)
#define FOR(i,a,b) for (int i = (a), _b = (b); i <= _b; i++)
#define FORD(i,a,b) for (int i = (a), _b = (b); i >= _b; i--)
#define FORN(i,a,b) for(int i=a;i<b;i++)
#define FOREACH(it,c) for (__typeof((c).begin()) it=(c).begin();it!=(c).end();it++)
#define RESET(c,x) memset (c, x, sizeof (c))
#define PI acos(-1)
#define sqr(x) ((x) * (x))
#define PB push_back
#define MP make_pair
#define F first
#define S second
#define Aint(c) (c).begin(), (c).end()
#define SIZE(c) (c).size()
#define DEBUG(x) { cerr << #x << " = " << x << endl; }
#define PR(a,n) {cerr<<#a<<" = "; FOR(_,1,n) cerr << a[_] << ' '; cerr <<endl;}
#define PR0(a,n) {cerr<<#a<<" = ";REP(_,n) cerr << a[_] << ' '; cerr << endl;}
#define LL long long
#define maxn 24
using namespace std;
int Gauss(int n, int a[][maxn * maxn], int b[]) {
for (int i = 0; i < n; i++) {
int row = -1;
for (int j = i; j < n; j++)
if (a[j][i]) {
row = j;
break;
}
if (row == -1) continue;
if (!a[i][i])
for (int j = 0; j <= n; j++)
a[i][j] ^= a[row][j];
for (int k = i; k < n; k++)
if (k != i && a[k][i] == 1) {
for (int j = 0; j <= n; j++)
a[k][j] ^= a[i][j];
}
}
for (int i = 0; i < n; i++)
if (a[i][n]) {
int ok = 0;
for (int j = 0; j < n; j++)
if (a[i][j]) {
ok = 1;
break;
}
if (!ok) return 0;
}
for (int i = n - 1; i >= 0; i--) {
if (a[i][i] == 0 && a[i][n] == 1) return 0;
if (a[i][i] == 0) b[i] = 0;
else b[i] = a[i][n];
if (b[i])
for (int j = i - 1; j >= 0; j--)
if (a[j][i] == 1) a[j][n] ^= 1;
}
return 1;
}
int n, d, g[maxn][maxn], a[maxn * maxn][maxn * maxn], root[maxn * maxn];
int main() {
cin >> n >> d;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> g[i][j];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
int row = i * n + j;
a[row][n * n] = g[i][j];
for (int x = 0; x < n; x++)
for (int y = 0; y < n; y++)
if (abs(x - i) + abs(y - j) <= d) {
// cerr << x * n + y << endl;
a[row][x * n + y] = 1;
}
}
int res = Gauss(n * n, a, root);
if (!res) cout << "Impossible" << endl;
else {
cout << "Possible" << endl;
int cnt = 0;
for (int i = 0; i < n * n; i++)
cnt += root[i];
cout << cnt << endl;
for (int i = 0; i < n * n; i++)
if (root[i]) cout << i / n << " " << i % n << endl;
}
return 0;
}
Tester’s Code
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 402;
int a[N][N],b[N];
vector<int> result;
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int n, d,i,j,k;
scanf("%d%d",&n,&d);
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
scanf("%d",b + i * n + j);
for (int x = max(i - d, 0); (x < n) && (x <= i + d); ++x) {
int dd = x - i;
if (dd < 0) {
dd = -dd;
}
dd = d - dd;
for (int y = max(j - dd, 0); (y < n) && (y <= j + dd); ++y) {
a[i * n + j][x * n + y] = 1;
}
}
}
}
int m = n * n;
for (i = 0; i < m; ++i) {
for (j = i; j < m; ++j) {
if (a[j][i]) {
break;
}
}
if (j < m) {
if (j != i) {
// exchange row j and row i
for (k = 0; k < m; ++k) {
int t = a[j][k];
a[j][k] = a[i][k];
a[i][k] = t;
}
k = b[i];
b[i] = b[j];
b[j] = k;
}
for (j = i + 1; j < m; ++j) {
if (a[j][i]) {
for (int k = i; k < m; ++k) {
a[j][k] ^= a[i][k];
}
b[j] ^= b[i];
}
}
}
}
for (i = m - 1; i >= 0; --i) {
for (j = i + 1; j < m; ++j) {
b[i] ^= (a[i][j] & b[j]);
}
if ((a[i][i] == 0) && (b[i] != 0)) {
break;
}
if (b[i]) {
result.push_back(i);
}
}
if (i < 0) {
puts("Possible");
printf("%d\n",result.size());
for (int i = 0; i < result.size(); ++i) {
printf("%d %d\n",result[i] / n, result[i] % n);
}
}
else {
puts("Impossible");
}
return 0;
}