Problem:
Score : 800 points

Problem Statement

There is a square grid with N rows and M columns.
Each square contains an integer: 0 or 1. The square at the i-th row from the top and the j-th column from the left contains a_{ij}.

Among the 2^{N+M} possible pairs of a subset A of the rows and a subset B of the columns, find the number of the pairs that satisfy the following condition, modulo 998244353:

The sum of the |A||B| numbers contained in the intersection of the rows belonging to A and the columns belonging to B, is odd.

Constraints

1 \leq N,M \leq 300

0 \leq a_{i,j} \leq 1(1\leq i\leq N,1\leq j\leq M)

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N M
a_{11} ... a_{1M}
:
a_{N1} ... a_{NM}

Output

Print the number of the pairs of a subset of the rows and a subset of the columns that satisfy the condition, modulo 998244353.

Sample Input 1

2 2
0 1
1 0

Sample Output 1

6

For example, if A consists of the first row and B consists of both columns, the sum of the numbers contained in the intersection is 0+1=1.

Sample Input 2

2 3
0 0 0
0 1 0

Sample Output 2

8

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Accepted)

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashSet;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.Set;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author prakharjain
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        EOddSubrectangles solver = new EOddSubrectangles();
        solver.solve(1, in, out);
        out.close();
    }

    static class EOddSubrectangles {
        int mod = 998244353;

        long pow(long a, long p, int mod) {
            if (p == 0) {
                return 1;
            }

            long t = pow(a, p / 2, mod);

            if (p % 2 != 0) {
                return (((t * t) % mod) * a) % mod;
            } else {
                return (t * t) % mod;
            }
        }

        public void solve(int testNumber, InputReader in, OutputWriter out) {

            int n = in.nextInt();
            int m = in.nextInt();
            int[][] a = new int[n][m];

            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    a[i][j] = in.nextInt();
                }
            }

            MatrixRank rank = new MatrixRank();

            int r = rank.matrixRankFF2(a);

            long ans = pow(2, n + m - 1, mod);
            ans -= pow(2, n + m - r - 1, mod);

            ans %= mod;

            if (ans < 0) {
                ans += mod;
            }

            out.println(ans);
        }

        class MatrixRank {
            int matrixRankFF2(int[][] a) {
                int n = a.length;
                int m = a[0].length;

//            Arrays.sort(a, (row1, row2) ->
//            {
//                for (int i = 0; i < m; i++) {
//                    if (row1[i] > row2[i]) {
//                        return -1;
//                    } else if (row1[i] < row2[i]) {
//                        return 1;
//                    }
//                }
//                return 0;
//            });
//
//            int rank = 0;
//
//            for (int i = 0; i < n; i++) {
//                int fsi = -1;
//                for (int j = 0; j < m; j++) {
//                    if (a[i][j] == 1) {
//                        fsi = j;
//                        break;
//                    }
//                }
//
//                if (fsi == -1) {
//                    return rank;
//                }
//
//                rank++;
//
//                for (int j = i + 1; j < n; j++) {
//                    if (a[j][fsi] == 1) {
//                        for (int k = fsi; k < m; k++) {
//                            a[j][k] = a[j][k] ^ a[i][k];
//                        }
//                    }
//                }
//
//                Arrays.sort(a, (row1, row2) ->
//                {
//                    for (int j = 0; j < m; j++) {
//                        if (row1[j] > row2[j]) {
//                            return -1;
//                        } else if (row1[j] < row2[j]) {
//                            return 1;
//                        }
//                    }
//                    return 0;
//                });
//            }
//
//            return rank;

                int rank = 0;

                Set<Integer> s = new HashSet<>();

                for (int i = 0; i < m; i++) {
                    int ind = -1;
                    for (int j = 0; j < n; j++) {
                        if (a[j][i] == 1 && !s.contains(j)) {
                            ind = j;
                            break;
                        }
                    }

                    if (ind == -1)
                        continue;

                    s.add(ind);
                    rank++;

                    for (int j = ind + 1; j < n; j++) {
                        if (a[j][i] == 1) {
                            for (int k = i; k < m; k++) {
                                a[j][k] ^= a[ind][k];
                            }
                        }
                    }
                }

                return rank;
            }

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void println(long i) {
            writer.println(i);
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int nextInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}