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;
}