#include <iostream>
#include <vector>
#include <cassert>
template <typename T>
struct Matrix
{
    static Matrix<T> I(const std::size_t N)
    {
        Matrix<T> ans(N, N);
        for (std::size_t i = 0; i < N; i++) { ans[i][i] = T(1); }
        return ans;
    }
    Matrix(const std::size_t R, const std::size_t C) : R{R}, C{C}, table(R, std::vector<T>(C, T(0))) {}
    const std::vector<T>& operator[](const std::size_t r) const { return table[r]; }
    std::vector<T>& operator[](const std::size_t r) { return table[r]; }
    Matrix<T> operator-() const
    {
        Matrix<T> ans(R, C);
        for (std::size_t i = 0; i < R; i++) {
            for (std::size_t j = 0; j < C; j++) { ans[i][j] = -table[i][j]; }
        }
        return ans;
    }
    Matrix<T> operator+(const Matrix<T>& m) const
    {
        assert(R == m.R and C == m.C);
        Matrix<T> ans(R, C);
        for (std::size_t i = 0; i < R; i++) {
            for (std::size_t j = 0; j < C; j++) { ans[i][j] = table[i][j] + m[i][j]; }
        }
        return ans;
    }
    Matrix<T> operator-(const Matrix<T>& m) const
    {
        assert(R == m.R and C == m.C);
        Matrix<T> ans(R, C);
        for (std::size_t i = 0; i < R; i++) {
            for (std::size_t j = 0; j < C; j++) { ans[i][j] = table[i][j] - m[i][j]; }
        }
        return ans;
    }
    Matrix<T> operator*(const Matrix<T>& m) const
    {
        assert(C == m.R);
        Matrix<T> ans(R, m.C);
        for (std::size_t i = 0; i < R; i++) {
            for (std::size_t j = 0; j < m.C; j++) {
                for (std::size_t k = 0; k < C; k++) { ans[i][j] += table[i][k] * m[k][j]; }
            }
        }
        return ans;
    }
    Matrix<T> operator*(const T& t) const
    {
        Matrix<T> ans(R, C);
        for (std::size_t i = 0; i < R; i++) {
            for (std::size_t j = 0; j < C; j++) { ans[i][j] = table[i][j] * t; }
        }
        return ans;
    }
    template <typename C>
    Matrix<T> operator^(const C n) const { return n == 0 ? I(R) : n % 2 == 1 ? (*this) * ((*this) ^ (n - 1)) : (((*this) * (*this)) ^ (n / 2)); }
    Matrix<T>& operator=(const Matrix<T>& m)
    {
        assert(R == m.R and C == m.C);
        for (std::size_t i = 0; i < R; i++) {
            for (std::size_t j = 0; j < C; j++) { table[i][j] = m[i][j]; }
        }
        return *this;
    }
    Matrix<T>& operator+=(const Matrix<T>& m)
    {
        assert(R == m.R and C == m.C);
        for (std::size_t i = 0; i < R; i++) {
            for (std::size_t j = 0; j < C; j++) { table[i][j] += m[i][j]; }
        }
    }
    Matrix<T>& operator-=(const Matrix<T>& m)
    {
        assert(R == m.R and C == m.C);
        for (std::size_t i = 0; i < R; i++) {
            for (std::size_t j = 0; j < C; j++) { table[i][j] -= m[i][j]; }
        }
        return *this;
    }
    Matrix<T>& operator*=(const Matrix<T>& m) { return *this = (*this) * m; }
    Matrix<T>& operator*=(const T& t)
    {
        for (std::size_t i = 0; i < R; i++) {
            for (std::size_t j = 0; j < C; j++) { table[i][j] *= t; }
        }
        return *this;
    }
    template <typename C>
    Matrix<T>& operator^=(const C n) { return (*this) = ((*this) ^ n); }
    const std::size_t R, C;
    std::vector<std::vector<T>> table;
};
template <typename T>
Matrix<T> operator*(const T& t, const Matrix<T>& m) { return m * t; }
template <typename T>
std::ostream& operator<<(std::ostream& os, const Matrix<T>& m)
{
    os << "[\n";
    for (std::size_t i = 0; i < m.R; i++) {
        os << "[";
        for (std::size_t j = 0; j < m.C; j++) { os << m[i][j] << " "; }
        os << "]\n";
    }
    return (os << "]\n");
}
template <typename T>
struct Vector
{
    Vector(const std::size_t R) : R{R}, table(R, T(0)) {}
    const T& operator[](const std::size_t r) const { return table[r]; }
    T& operator[](const std::size_t r) { return table[r]; }
    Vector<T> operator+(const Vector<T>& v) const
    {
        assert(R == v.R);
        Vector<T> ans(R);
        for (std::size_t i = 0; i < R; i++) { ans[i] = table[i] + v[i]; }
        return ans;
    }
    Vector<T> operator-(const Vector<T>& v) const
    {
        assert(R == v.R);
        Vector<T> ans(R);
        for (std::size_t i = 0; i < R; i++) { ans[i] = table[i] - v[i]; }
        return ans;
    }
    Vector<T> operator*(const T& t) const
    {
        Vector<T> ans(R);
        for (std::size_t i = 0; i < R; i++) { ans[i] = table[i] * t; }
        return ans;
    }
    Vector<T>& operator=(const Vector<T>& v)
    {
        assert(R == v.R);
        for (std::size_t i = 0; i < R; i++) { table[i] = v[i]; }
        return *this;
    }
    Vector<T>& operator+=(const Vector<T>& v)
    {
        assert(R == v.R);
        for (std::size_t i = 0; i < R; i++) { table[i] += v[i]; }
        return *this;
    }
    Vector<T>& operator-=(const Vector<T>& v)
    {
        assert(R == v.R);
        for (std::size_t i = 0; i < R; i++) { table[i] -= v[i]; }
        return *this;
    }
    Vector<T>& operator*=(const T& t)
    {
        Vector<T> ans(R);
        for (std::size_t i = 0; i < R; i++) { table[i] *= t; }
        return *this;
    }
    const std::size_t R;
    std::vector<T> table;
};
template <typename T>
Vector<T> operator*(const T& t, const Vector<T>& v) { return v * t; }
template <typename T>
Vector<T> operator*(const Matrix<T>& m, const Vector<T>& v)
{
    assert(m.C == v.R);
    Vector<T> ans(m.R);
    for (std::size_t i = 0; i < m.R; i++) {
        for (std::size_t j = 0; j < m.C; j++) { ans[i] += m[i][j] * v[j]; }
    }
    return ans;
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const Vector<T>& v)
{
    os << "[\n";
    for (std::size_t i = 0; i < v.R; i++) { os << v[i] << "\n"; }
    return (os << "]\n");
}
template <typename T>
struct TVector
{
    TVector(const std::size_t C) : C{C}, table(C, T(0)) {}
    const T& operator[](const std::size_t c) const { return table[c]; }
    T& operator[](const std::size_t c) { return table[c]; }
    TVector<T> operator+(const TVector<T>& v) const
    {
        assert(C == v.C);
        TVector<T> ans(C);
        for (std::size_t i = 0; i < C; i++) { ans[i] = table[i] + v[i]; }
        return ans;
    }
    TVector<T> operator-(const TVector<T>& v) const
    {
        assert(C == v.C);
        TVector<T> ans(C);
        for (std::size_t i = 0; i < C; i++) { ans[i] = table[i] - v[i]; }
        return ans;
    }
    TVector<T> operator*(const T& t) const
    {
        TVector<T> ans(C);
        for (std::size_t i = 0; i < C; i++) { ans[i] = table[i] * t; }
        return ans;
    }
    TVector<T>& operator=(const TVector<T>& v)
    {
        assert(C == v.C);
        for (std::size_t i = 0; i < C; i++) { table[i] = v[i]; }
        return *this;
    }
    TVector<T>& operator+=(const TVector<T>& v)
    {
        assert(C == v.C);
        for (std::size_t i = 0; i < C; i++) { table[i] += v[i]; }
        return *this;
    }
    TVector<T>& operator-=(const TVector<T>& v)
    {
        assert(C == v.C);
        for (std::size_t i = 0; i < C; i++) { table[i] -= v[i]; }
        return *this;
    }
    TVector<T>& operator*=(const T& t)
    {
        TVector<T> ans(C);
        for (std::size_t i = 0; i < C; i++) { table[i] *= t; }
        return *this;
    }
    const std::size_t C;
    std::vector<T> table;
};
template <typename T>
TVector<T> operator*(const T& t, const TVector<T>& v) { return v * t; }
template <typename T>
TVector<T> operator*(const TVector<T>& v, const Matrix<T>& m)
{
    assert(v.C == m.R);
    TVector<T> ans(m.C);
    for (std::size_t i = 0; i < m.C; i++) {
        for (std::size_t j = 0; j < m.R; j++) { ans[i] += v[j] * m[j][i]; }
    }
    return ans;
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const TVector<T>& v)
{
    os << "[ ";
    for (std::size_t i = 0; i < v.C; i++) { os << v[i] << " "; }
    return (os << "]\n");
}
// template <typename T>
// std::size_t Rank(Matrix<T> mat)
// {
//     std::size_t r = 0;
//     for (std::size_t c = 0; c < mat.C; c++) {
//         if (r == mat.R) { return r; }
//         std::size_t piv = r;
//         for (; piv < mat.R and mat[piv][c] == 0; piv++) {}
//         if (piv == mat.R) { continue; }
//         std::swap(mat[r], mat[piv]);
//         const T p = mat[r][c];
//         for (std::size_t i = r; i < mat.R; i++) { mat[i][c] /= p; }
//         for (std::size_t j = 0; j < mat.C; j++) {
//             if (j == c) { continue; }
//             const T p = mat[r][j];
//             for (std::size_t i = 0; i < mat.R; i++) { mat[i][j] -= p * mat[i][c]; }
//         }
//         r++;
//     }
//     return r;
// }
template <typename T>
std::size_t Rank(Matrix<T> mat)
{
    std::size_t r = 0;
    for (std::size_t c = 0; c < mat.C; c++) {
        if (r == mat.R) { return r; }
        std::size_t piv = r;
        for (; piv < mat.R and mat[piv][c] == 0; piv++) {}
        if (piv == mat.R) { continue; }
        std::swap(mat[piv], mat[r]);
        for (std::size_t j = c + 1; j < mat.C; j++) { mat[r][j] /= mat[r][c]; }
        for (std::size_t j = r + 1; j < mat.R; j++) {
            for (std::size_t k = c + 1; k < mat.C; k++) { mat[j][k] -= mat[r][k] * mat[j][c]; }
        }
        r++;
    }
    return r;
}
using ll = long long;
using ll = long long;
template <typename T>
constexpr T MOD() { return 1000000007; }
template <typename T, T mod = MOD<T>()>
class ModInt
{
private:
    T value;
    static T pow(const T p, const T n) { return p < 0 ? pow(mod + p, n) : n == 0 ? 1 : n % 2 == 1 ? pow(p, n - 1) * p % mod : pow(p * p % mod, n / 2); }
    static T inv(const T p) { return pow(p, mod - 2); }

public:
    ModInt() : value{0} {}
    ModInt(const T val) : value{((val % mod) + mod) % mod} {}
    ModInt(const ModInt<T, mod>& n) : value{n()} {}
    ModInt<T, mod>& operator=(const ModInt<T, mod>& n) { return value = n(), (*this); }
    ModInt<T, mod>& operator=(const T v) { return value = (mod + v % mod) % mod, (*this); }
    ModInt<T, mod> operator+() const { return *this; }
    ModInt<T, mod> operator-() const { return ModInt{mod - value}; }
    ModInt<T, mod> operator+(const ModInt<T, mod>& val) const { return ModInt{value + val()}; }
    ModInt<T, mod> operator-(const ModInt<T, mod>& val) const { return ModInt{value - val() + mod}; }
    ModInt<T, mod> operator*(const ModInt<T, mod>& val) const { return ModInt{value * val()}; }
    ModInt<T, mod> operator/(const ModInt<T, mod>& val) const { return ModInt{value * inv(val())}; }
    ModInt<T, mod>& operator+=(const ModInt<T, mod>& val) { return (((value += val()) %= mod) += mod) %= mod, (*this); }
    ModInt<T, mod>& operator-=(const ModInt<T, mod>& val) { return (((value -= val()) %= mod) += mod) %= mod, (*this); }
    ModInt<T, mod>& operator*=(const ModInt<T, mod>& val) { return (((value *= val()) %= mod) += mod) %= mod, (*this); }
    ModInt<T, mod>& operator/=(const ModInt<T, mod>& val) { return (((value *= inv(val())) %= mod) += mod) %= mod, (*this); }
    ModInt<T, mod> operator+(const T val) const { return ModInt{value + val}; }
    ModInt<T, mod> operator-(const T val) const { return ModInt{value - val}; }
    ModInt<T, mod> operator*(const T val) const { return ModInt{value * val}; }
    ModInt<T, mod> operator/(const T val) const { return ModInt{value * inv(val)}; }
    ModInt<T, mod>& operator+=(const T val) { return (((value += val) %= mod) += mod) %= mod, (*this); }
    ModInt<T, mod>& operator-=(const T val) { return (((value -= val) %= mod) += mod) %= mod, (*this); }
    ModInt<T, mod>& operator*=(const T val) { return (((value *= val) %= mod) += mod) %= mod, (*this); }
    ModInt<T, mod>& operator/=(const T val) { return (((value *= inv(val)) %= mod) += mod) %= mod, (*this); }
    bool operator==(const ModInt<T, mod>& val) const { return value == val.value; }
    bool operator!=(const ModInt<T, mod>& val) const { return not(*this == val); }
    bool operator==(const T val) const { return value == (mod + val % mod) % mod; }
    bool operator!=(const T val) const { return not(*this == val); }
    T operator()() const { return value; }
};
template <typename T, T mod>
inline ModInt<T, mod> operator+(const T val, const ModInt<T, mod>& n) { return ModInt<T, mod>{n() + val}; }
template <typename T, T mod>
inline ModInt<T, mod> operator-(const T val, const ModInt<T, mod>& n) { return ModInt<T, mod>{-n() + val}; }
template <typename T, T mod>
inline ModInt<T, mod> operator*(const T val, const ModInt<T, mod>& n) { return ModInt<T, mod>{n() * val}; }
template <typename T, T mod>
inline ModInt<T, mod> operator/(const T val, const ModInt<T, mod>& n) { return ModInt<T, mod>(val) / n; }
template <typename T, T mod>
inline bool operator==(const T val, const ModInt<T, mod>& n) { return n == val; }
template <typename T, T mod>
inline bool operator!=(const T val, const ModInt<T, mod>& n) { return not(val == n); }
template <typename T, T mod>
inline std::istream& operator>>(std::istream& is, ModInt<T, mod>& n)
{
    T v;
    return is >> v, n = v, is;
}
template <typename T, T mod>
std::ostream& operator<<(std::ostream& os, const ModInt<T, mod>& n) { return (os << n()); }
using mint = ModInt<int, MOD<int>()>;
using mll = ModInt<ll, MOD<ll>()>;
constexpr int MOD2 = 998244353;
int main()
{
    std::size_t N, M;
    std::cin >> N >> M;
    Matrix<ModInt<int, 2>> a(N, M);
    for (std::size_t i = 0; i < N; i++) {
        for (std::size_t j = 0; j < M; j++) { std::cin >> a[i][j]; }
    }
    const std::size_t R = Rank(a);
    std::vector<int> bp(600, 1);
    for (std::size_t i = 1; i < 600; i++) { bp[i] = bp[i - 1] * 2 % MOD2; }
    std::cout << (bp[N + M - 1] - bp[N + M - R - 1] + MOD2) % MOD2 << std::endl;
    return 0;
}


Measured memory_bytes: 1024