Problem:
成績上昇大作戦
受験生の太郎君は
N
日間の勉強合宿に参加した．
この合宿では毎日
M
科目のテストを行い，
合宿の終了後にはすべてのテストの点数が書かれた成績表が配られる．
成績表は
N
枚の紙からなっており，
i
枚目の紙には
i
日目の全
M
科目のテストの科目名と点数のみが印刷されている．
成績表に日付が書かれていないことに気付いた太郎君は，お母さんに成績表を渡す前に細工を加えることにした．
成績表の紙の順番を並べ替え，さらに1枚目から順番にページ番号を書き込んで冊子にすることによって「偽りの成績表」を作ったのだ．
太郎君の目的は，「偽りの成績表」でテストの点数がページ番号に対して広義単調増加している科目の個数を最大化することである．
太郎君が「偽りの成績表」を作るとき，テストの点数がページ番号に対して広義単調増加である科目の個数の最大値を求めよ．
ただし，
N
日間のテストの点数がページ番号に対して広義単調増加であるとは
1 ≤ i < N
に対して
i+1
枚目に記載されている点数が
i
枚目に記載されている点数以上であることを意味する．
Input
入力は 50 個以下のデータセットからなる． 各データセットは次の形式で表される．
N
M
a
11
...
a
1M
...
a
N1
...
a
NM
1行目には，勉強合宿の日数
N
と科目数
M
が与えられる．
N
は
1
以上
10
3
以下の整数で，
M
は
1
以上
40
以下の整数である．
続く
N
行には太郎君の点数が与えられる．各行は
M
個の整数からなっており
a
ij
は太郎君の
i
日目の科目
j
の点数であり，
a
ij
は
0
以上
10
3
以下の整数である．
入力の終わりは，2 つのゼロからなる行で表される．
Output
各データセットについて，テストの点数がページ番号に対して広義単調増加である科目の個数の最大値を 1 行に出力せよ．
Sample Input
3 3
1 2 3
2 1 3
3 3 3
8 5
3 3 4 3 4
2 1 2 3 2
7 9 7 8 7
3 4 3 3 4
1 2 2 3 2
4 5 6 5 6
7 9 7 7 8
4 5 5 6 6
5 5
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
5 9
1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5
0 0
Output for the Sample Input
2
3
1
9

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
#include <atcoder/all>
using namespace std;
using namespace atcoder;
using mint = modint998244353;

//多倍長整数//
//#include <boost/multiprecision/cpp_int.hpp>
//namespace mp = boost::multiprecision;
//using bint = mp::cpp_int;

const int INF = 2e9;
const int MOD = 998244353;
const long long LINF = 5e18;

using ll = long long;
using vi = vector<int>;
using vl = vector<long long>;
using vs = vector<string>;
using vc = vector<char>;
using vb = vector<bool>;
using vvi = vector<vector<int>>;
using vvvi = vector<vector<vector<int>>>;
using vvvvi = vector<vector<vector<vector<int>>>>;
using vvl = vector<vector<long long>>;
using vvvl = vector<vector<vector<long long>>>;
using vvvvl = vector<vector<vector<vector<long long>>>>;
using vvc = vector<vector<char>>;
using vvb = vector<vector<bool>>;
using vvvb = vector<vector<vector<bool>>>;
using vvvvb = vector<vector<vector<vector<bool>>>>;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define dump(x)  cout << #x << " = " << (x) << endl;
#define Yes(n) cout << ((n) ? "Yes" : "No"  ) << endl
#define ALL(obj) (obj).begin(),(obj).end()

vector<int> max_independent(int n, vector<vector<bool>> g){
	int mid = n / 2;
	vector<bool> is_ind1(1<<mid, true);
	for(int i = 0;i < mid - 1;i++){
		for(int j = i + 1;j < mid;j++){
			if(g[i][j]) is_ind1[(1<<i) | (1<<j)] = false;
		}
	}
	for(int i = 0;i < (1<<mid);i++){
		if(!is_ind1[i]){
			for(int j = 0;j < mid;j++){
				if((i & (1<<j)) == 0){
					is_ind1[i | (1<<j)] = false;
				}
			}
		}
	}

	vector<bool> is_ind2(1<<(n - mid), true);
	for(int i = 0;i < (n - mid) - 1;i++){
		for(int j = i + 1;j < (n - mid);j++){
			if(g[mid + i][mid + j]) is_ind2[(1<<i) | (1<<j)] = false;
		}
	}
	for(int i = 0;i < (1<<(n - mid));i++){
		if(!is_ind2[i]){
			for(int j = 0;j < (n - mid);j++){
				if((i & (1<<j)) == 0){
					is_ind2[i | (1<<j)] = false;
				}
			}
		}
	}

	vector<int> not_connect(1<<mid);
	not_connect[0] = (1<<(n - mid)) - 1;
	for(int i = 0;i < mid;i++){
		for(int j = mid;j < n;j++){
			if(!g[i][j]) not_connect[1<<i] |= 1<<(j - mid);
		}
	}

	for(int i = 0;i < (1<<mid);i++){
		for(int j = 0;j < mid;j++){
			if((i & (1<<j)) == 0){
				not_connect[i | (1<<j)] = not_connect[i] & not_connect[1<<j];
			}
		}
	}

	vector<int> mx_sub_ind(1<<(n - mid));
	for(int i = 0;i < (1<<(n - mid));i++){
		if(is_ind2[i]) mx_sub_ind[i] = i;
		else mx_sub_ind[i] = 0;
	}

	for(int i = 0;i < (1<<(n - mid));i++){
		for(int j = 0;j < (n - mid);j++){
			if((i & (1<<j)) == 0 && __popcount(mx_sub_ind[i | (1<<j)]) < __popcount(mx_sub_ind[i])){
				mx_sub_ind[i | (1<<j)] = mx_sub_ind[i];
			}
		}
	}

	ll ans = 0;
	for(int i = 0;i < (1<<mid);i++){
		if(is_ind1[i]){
			ll cur = i | ((ll)mx_sub_ind[not_connect[i]] << mid);
			if(__popcount(ans) < __popcount(cur)){
				ans = cur;
			}
		}
	}

	vector<int> ret;
	rep(i,n)if(ans & (1LL<<i)) ret.push_back(i);
	return ret;
}

int main(){
	while(1){
        int n, m;
        cin >> n >> m;
        if(n == 0) return 0;
        vvi a(n, vi(m));
        rep(i,n)rep(j,m) cin >> a[i][j];
        vvb g(m, vb(m, false));
        for(int i = 0;i < m - 1;i++){
            for(int j = i + 1;j < m;j++){
                vector<pair<int,int>> vp(n);
                rep(k,n) vp[k] = {a[k][i], a[k][j]};
                sort(ALL(vp));
                bool ok = true;
                rep(k, n - 1) if(vp[k].second > vp[k + 1].second) ok = false;
                if(!ok){
                    g[i][j] = true;
                    g[j][i] = true;
                }
            }
        }
        cout << max_independent(m, g).size() << '\n';
    }
	return 0;
}
accuracy: 1
time_ms: 1330
memory_kb: 14288
final_rank: 12

code_snippet: // (⁠◕⁠ᴗ⁠◕⁠✿⁠)

// #pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define srep(i, s, n) for (ll i = s; i < (n); i++)
#define len(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
using namespace std;
template<typename T> using vc = vector<T>;
template<typename T> using vv = vc<vc<T>>;
template<typename T> using vvv = vv<vc<T>>;
using vi = vc<int>;using vvi = vv<int>; using vvvi = vv<vi>;
using ll = long long;using vl = vc<ll>;using vvl = vv<ll>; using vvvl = vv<vl>;
using ld = long double; using vld = vc<ld>; using vvld = vc<vld>; using vvvld = vc<vvld>;
using uint = unsigned int;
using ull = unsigned long long;
const ld pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
// const ll mod = 1000000007;
const ll mod = 998244353;
inline bool inside(ll y, ll x, ll H, ll W) {return 0 <= (y) and (y) < (H) and 0 <= (x) and (x) < (W); }

#define debug(var) do { cout << #var << " :\n"; view(var); } while(0)
template<typename T>void view(const T& e) {cout << e;}
template<typename T1, typename T2>void view(const pair<T1, T2>& p) {cout << "{" << p.first << ", " << p.second << "}";}
template<typename T>void view(const vc<T>& v) {for (const auto& e : v) {view(e);cout << " ";} cout << endl;}
template<typename T>void view(const vv<T>& vv) {for (const auto& v : vv) {view(v);cout << " ";} cout << endl;}
template<typename T>void view(const set<T>& s) {for (const auto& e : s) {view(e);cout << " ";} cout << endl;}
template<typename T>void view(const unordered_set<T>& s) {for (const auto& e : s) {view(e);cout << " ";} cout << endl;}
template<typename T1, typename T2>void view(const map<T1, T2>& mp){for (const auto& e : mp) {view(e);cout << " ";} cout << endl;}

int N, M;

void solve(){
    vvi A(M, vi(N)); rep(j, N) rep(i, M) cin >> A[i][j];
    if (M == 1){
        cout << 1 << endl;
        return;
    }
    int X = M / 2, Y = M - X;
    vi okX(X, 0), okY(Y, 0), okX2Y(X, 0);
    vi P(N); iota(all(P), 0);
    rep(j, X) rep(i, j + 1){
        sort(all(P), [&](auto a, auto b){return (A[i][a] == A[i][b] ? A[j][a] < A[j][b] : A[i][a] < A[i][b]);});
        bool ok = true;
        rep(k, N - 1) if (A[j][P[k]] > A[j][P[k + 1]]){
            ok = false;
            break;
        }
        if (ok){
            okX[i] |= (1 << j);
            okX[j] |= (1 << i);
        }
    }
    rep(i, X) rep(j, Y){
        sort(all(P), [&](auto a, auto b){return (A[i][a] == A[i][b] ? A[j + X][a] < A[j + X][b] : A[i][a] < A[i][b]);});
        bool ok = true;
        rep(k, N - 1) if (A[j + X][P[k]] > A[j + X][P[k + 1]]){
            ok = false;
            break;
        }
        if (ok){
            okX2Y[i] |= (1 << j);
        }
    }
    rep(j, Y) rep(i, j + 1){
        sort(all(P), [&](auto a, auto b){return (A[i + X][a] == A[i + X][b] ? A[j + X][a] < A[j + X][b] : A[i + X][a] < A[i + X][b]);});
        bool ok = true;
        rep(k, N - 1) if (A[j + X][P[k]] > A[j + X][P[k + 1]]){
            ok = false;
            break;
        }
        if (ok){
            okY[i] |= (1 << j);
            okY[j] |= (1 << i);
        }
    }
    
    // cout << X << " " << Y << endl;
    // rep(i, X) cout << bitset<3>(okX[i]) << endl;
    // rep(i, Y) cout << bitset<3>(okY[i]) << endl;
    // rep(i, X) cout << bitset<3>(okX2Y[i]) << endl;
    vi dp(1 << Y, 0);
    rep(cmb, 1 << Y){
        int ok = (1 << Y) - 1;
        rep(i, Y) if (cmb >> i & 1) ok &= okY[i];
        if ((cmb & ok) == cmb) dp[cmb] = __builtin_popcount(cmb);
    }
    rep(y, Y) rep(cmb, 1 << Y) if ((~cmb >> y & 1)) dp[cmb | (1 << y)] = max(dp[cmb | (1 << y)], dp[cmb]);
    int ans = 0;
    rep(cmb, 1 << X){
        int ok = (1 << X) - 1;
        rep(i, X) if (cmb >> i & 1) ok &= okX[i];
        if((cmb & ok) == cmb){
            int subok = (1 << Y) - 1;
            rep(i, X) if (cmb >> i & 1) subok &= okX2Y[i];
            ans = max(ans, __builtin_popcount(cmb) + dp[subok]);
        }
    }
    cout << ans << endl;
}

int main(){
    while (true){
        cin >> N >> M;
        if (N == 0) break;
        solve();
    }
}
accuracy: 1
time_ms: 770
memory_kb: 8544
final_rank: 5

code_snippet: #include <bits/stdc++.h>
#include <unordered_map>
#include <stdlib.h>
using namespace std;
#define rep(i, a, n) for(ll i = a; i < n; i++)
#define rrep(i, a, n) for(ll i = a; i >= n; i--)
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define all(x) (x).begin(), (x).end()
//constexpr ll MOD = 1000000007;
constexpr ll MOD = 998244353;
constexpr int IINF = 1001001001;
constexpr ll INF = 1LL<<60;
template<class t,class u> void chmax(t&a,u b){if(a<b)a=b;}
template<class t,class u> void chmin(t&a,u b){if(b<a)a=b;}


ll gcd(ll a, ll b){
    if(a%b == 0){
      return b;
    }else{
      return gcd(b, a%b);
    }
}

ll lcm(ll a, ll b){
    return a*b / gcd(a, b);
}

ll powMod(ll x, ll n) {
    if (n == 0) return 1 % MOD;
    ll val = powMod(x, n / 2);
    val *= val;
    val %= MOD;
    if (n % 2 == 1) val *= x;
    return val % MOD;
}

int main() {
    while(true){
        ll n, m; cin >> n >> m;
        if(n*m == 0) break;
        vector<vector<ll>> a(m,vector<ll>(n));
        rep(i,0,n)rep(j,0,m) cin >> a[j][i];
        if(m == 1){
            cout << 1 << endl;
            continue;
        }
        vector<vector<ll>> g(m,vector<ll>(m,0));
        vector<pll> vec(n);
        rep(i,0,m)rep(j,i+1,m){
            rep(k,0,n) vec[k] = {a[i][k], a[j][k]};
            sort(all(vec));
            ll f = 1;
            rep(k,0,n-1){
                if(vec[k].first > vec[k+1].first || vec[k].second > vec[k+1].second){
                    f = 0;
                    break;
                }
            }
            if(f){
                g[i][j] = g[j][i] = 1;
            }
        }
        rep(i,0,m)rep(j,0,m){
            if(i == j) continue;
            g[i][j] = 1-g[i][j];
        }
        ll b = m/2;
        vector<ll> dp1(1<<b,0), dp2(1<<(m-b),0);
        {
            rep(i,0,1<<b){
                ll f = 1;
                rep(j,0,b)rep(k,j+1,b){
                    if((i >> j & 1) && (i >> k & 1)){
                        if(g[j][k]){
                            f = 0;
                            break;
                        }
                    }
                }
                if(f) dp1[i] = __popcount(i);
            }
        }
        {
            rep(i,0,1<<(m-b)){
                ll f = 1;
                rep(j,b,m)rep(k,j+1,m){
                    if((i >> (j-b) & 1) && (i >> (k-b) & 1)){
                        if(g[j][k]){
                            f = 0;
                            break;
                        }
                    }
                }
                if(f) dp2[i] = __popcount(i);
                rep(j,0,(m-b)){
                    if(i >> j & 1){
                        chmax(dp2[i], dp2[i^(1<<j)]);
                    }
                }
            }
        }
        ll ans = 1;
        rep(i,0,1<<b){
            if(i != 0 && dp1[i] == 0) continue;
            ll bit = (1<<(m-b))-1;
            rep(j,0,b){
                if(i >> j & 1){
                    rep(k,b,m){
                        if(g[j][k] && (bit >> (k-b) &1)) bit ^= (1<<(k-b));
                    }
                }
            }
            chmax(ans,__popcount(i) + dp2[bit]);
        }
        cout << ans << endl;
        // rep(i,0,1<<b) cout << dp1[i] << " ";
        // cout << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 2940
memory_kb: 20084
final_rank: 17

code_snippet: #include <bits/extc++.h>

using namespace std;
using ll = long long;
#define REP(i, n) for (ll i = 0; i < ll(n); i++)
#define FOR(i, j, n) for (ll i = j; i < n; i++)
#define ALL(n) (n).begin(), (n).end()
#define P pair<ll, ll>
int main() {
  ll n, m;
  while (1) {
    cin >> n >> m;
    if (n == 0 and m == 0) {
      return 0;
    }
    ll k1 = (m + 1) / 2, k2 = m - k1;
    vector<vector<ll>> s(n, vector<ll>(m));
    vector<vector<bool>> ok(m, vector<bool>(m, true));
    REP(i, n) {
      REP(j, m) {
        cin >> s[i][j];
      }
    }
    if (m == 1) {
      cout << 1 << endl;
      continue;
    }
    REP(j, m) {
      vector<P> v;
      REP(i, n) {
        v.push_back(P(s[i][j], i));
      }
      sort(ALL(v));
      vector<ll> ma(m, -1), cma(m, -1);
      REP(i, n) {
        REP(k, m) {
          if (j == k) continue;
          if (ma[k] > s[v[i].second][k]) ok[j][k] = ok[k][j] = false;
          cma[k] = max(cma[k], s[v[i].second][k]);
        }
        if (i + 1 < n and v[i].first < v[i + 1].first) {
          REP(k, m) {
            ma[k] = max(ma[k], cma[k]);
          }
        }
      }
    }

    vector<bool> b1(1ll << k1), b2(1ll << k2);

    b1[0] = b2[0] = true;
    REP(i, 1ll << k1) {
      if (i == 0) continue;
      ll now = i, c = 0;
      while (!(now & 1)) {
        c++;
        now >>= 1;
      }
      ll f = i - (1 << c);
      if (!b1[f]) continue;
      bool ook = true;
      REP(j, k1) {
        if (f & (1ll << j)) {
          if (!ok[j][c]) ook = false;
        }
      }
      if (ook) {
        b1[i] = true;
        // cerr << "b1 " << i << endl;
      }
    }

    vector<ll> dp(1ll << k2);
    REP(i, 1ll << k2) {
      if (i == 0) continue;
      ll now = i, c = 0;
      while (!(now & 1)) {
        c++;
        now >>= 1;
      }
      ll f = i - (1 << c);
      if (!b2[f]) continue;
      bool ook = true;
      REP(j, k2) {
        // cout << i << " " << j << " " << c << " " << k1 << " " << k2 << endl;
        if (f & (1ll << j)) {
          if (!ok[j + k1][c + k1]) ook = false;
        }
      }
      if (ook) {
        b2[i] = true;
        dp[i] = __popcount((uint64_t)i);
        // cerr << "b2 " << i << endl;
      }
    }

    REP(j, k2) {
      ll bit = 1ll << j;
      REP(i, 1 << k2) {
        if (i & bit) dp[i] = max(dp[i], dp[i ^ bit]);
      }
    }
    vector<ll> g(k1);
    REP(i, k1) {
      REP(j, k2) {
        if (ok[i][j + k1]) {
          g[i] |= 1ll << j;
        }
      }
    }
    ll ans = 0;

    REP(i, 1ll << k1) {
      if (!b1[i]) continue;
      ll msk = (1ll << k2) - 1;
      REP(j, k1) {
        if (i & (1ll << j)) {
          msk &= g[j];
        }
      }
      // cerr << i << " " << msk << " " << dp[msk] << endl;
      ans = max(ans, dp[msk] + __popcount((uint64_t)i));
    }
    cout << ans << endl;
  }
}
accuracy: 1
time_ms: 420
memory_kb: 14092
final_rank: 8

code_snippet: #include <bits/extc++.h>

using namespace std;

#define rep(i,n) for(int i=0;i<(n);++i)
#define reps(i,n) for(int i=1;i<=(n);++i)
#define all(x) begin(x),end(x)
#define updiv(a, b) (((a) + (b) - 1) / (b))
using ll = long long;
using ull = unsigned long long;
constexpr int INF  = 0x3f3f3f3f;
constexpr long long LINF = 0x3f3f3f3f3f3f3f3fLL;
constexpr int mod1 = 1000000007;
constexpr int mod2 = 998244353;

template <class Func>
class FixPoint : Func {
public:
    explicit constexpr FixPoint(Func&& f) noexcept : Func(forward<Func>(f)) {}

    template <class... Args>
    constexpr decltype(auto) operator()(Args&&... args) const {
        return Func::operator()(*this, std::forward<Args>(args)...);
    }
};

template <class Func>
static inline constexpr decltype(auto) makeFixPoint(Func&& f) noexcept {
    return FixPoint<Func>{forward<Func>(f)};
}

template <class T, class It = decltype(std::begin(std::declval<T>()))>
inline constexpr auto Indexed(T&& iterable) {
    struct Iterator {
        size_t index;
        It it;
        constexpr bool operator!= (const Iterator& other) const { return it != other.it; }
        constexpr void operator++() { ++index; ++it; }
        constexpr void operator--() { --index; --it; }
        constexpr auto operator*() const { return std::tie(index, *it); }
    };
    struct IterableWrapper {
        T iterable;
        constexpr auto begin() { return Iterator{ 0, std::begin(iterable) }; }
        constexpr auto end() { return Iterator{ std::size(iterable), std::end(iterable) }; }
    };
    return IterableWrapper{ std::forward<T>(iterable) };
}

// {f(i) | i in [begin, left) ∪ (right, rbegin]}
template<class It, class F>
pair<It, reverse_iterator<It> > bsearch(It begin, It end, const F &f) {
    auto rbegin = reverse_iterator(end), rend = reverse_iterator(begin);
    if (begin == end) return make_pair(end, rend);
    It left; reverse_iterator<It> right;
    if (f(*begin)) {
        auto l = begin, r = end;
        while (r - l > 1) {
            auto mid = l + (r - l) / 2;
            if (f(*mid)) l = mid; else r = mid;
        }
        left = r;
    } else left = begin;
    if (f(*rbegin)) {
        auto l = rbegin, r = rend;
        while (r - l > 1) {
            auto mid = l + (r - l) / 2;
            if (f(*mid)) l = mid; else r = mid;
        }
        right = r;
    } else right = rbegin;
    return make_pair(left, right);
}

template<class T, class U> istream& operator>>(istream& is, pair<T, U>& p){ is >> p.first >> p.second; return (is); }
template<class T, class U> ostream& operator<<(ostream& os, pair<T, U>& p){ os << p.first << ' ' << p.second; return (os); }
template<class T> istream& operator>>(istream& is, vector<T>& v){ for (auto &&e : v) is >> e; return (is); }
template<class T> ostream& operator<<(ostream& os, vector<T>& v){ for (auto &&e : v) os << e << ' '; return (os); }

template<class T> inline const T& max(const vector<T> &v) { return *max_element(v.begin(), v.end()); }
template<class T> inline const T& min(const vector<T> &v) { return *min_element(v.begin(), v.end()); }
template<class T> inline T mex(vector<T> v) {
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
    for (T i = 0; i < (T) v.size(); ++i) if (v[i] != i) return i;
    return v.size();
}
template<class T> inline T mex(initializer_list<T> l) { return mex(vector<T>(l)); }

template <class A, class B> inline bool chmax(A &a, const B &b) { return b > a && (a = b, true); }
template <class A, class B> inline bool chmin(A &a, const B &b) { return b < a && (a = b, true); }

template <class T> using max_heap = priority_queue<T>;
template <class T> using min_heap = priority_queue<T, vector<T>, greater<T> >;
template <class A, class B> using umap = unordered_map<A, B>;
template <class T> using uset = unordered_set<T>;

template <class T> using Max_Heap = __gnu_pbds::priority_queue<T, less<T>, __gnu_pbds::rc_binomial_heap_tag>;
template <class T> using Min_Heap = __gnu_pbds::priority_queue<T, greater<T>, __gnu_pbds::rc_binomial_heap_tag>;
template <class T> using Set = __gnu_pbds::tree<T, __gnu_pbds::null_type, less<T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
template <class K, class V> using Umap = __gnu_pbds::gp_hash_table<K, V>;
template <class T> using Rope = __gnu_cxx::rope<T>;

template <class T> void bye(T x){ cout << x << '\n'; exit(0); }

constexpr int dx[] = {1,0,-1,0,1,1,-1,-1,0};
constexpr int dy[] = {0,1,0,-1,1,-1,-1,1,0};

struct XorShift {
private:
    constexpr static double R = 1.0 / 0xffffffff;
    uint64_t x;

    public:
    explicit XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}

    template< typename T = uint64_t >
    inline T get() { // [0, 2^64)
        x ^= x << 7ull;
        x ^= x >> 9ull;
        return x;
    }

    inline uint32_t get(uint32_t r) { // [0, r)
        return ((uint64_t) get< uint32_t >() * r) >> 32ull;
    }

    inline uint32_t get(uint32_t l, uint32_t r) { // [l, r)
        return l + get(r - l);
    }

    inline double probability() { // [0.0, 1.0]
        return get< uint32_t >() * R;
    }
} rnd;

int main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout.setf(ios_base::fixed);
    cout.precision(12);

    int n, m;
    while (cin >> n >> m, n) {

        vector a(n, vector(m, int()));

        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                cin >> a[i][j];
            }
        }

        vector g(m, ll());

        for (int i = 0; i < m; ++i) {
            for (int j = i + 1; j < m; ++j) {
                vector<int> ord(n);
                iota(ord.begin(), ord.end(), 0);
                sort(ord.begin(), ord.end(), [&](int p, int q) {
                    return a[p][i] != a[q][i] ? a[p][i] < a[q][i] : a[p][j] < a[q][j];
                });
                for (int k = 0; k + 1 < n; ++k) {
                    if (a[ord[k]][i] < a[ord[k + 1]][i] && a[ord[k]][j] > a[ord[k + 1]][j]) goto ng;
                }
                g[j] |= 1LL << i;
                g[i] |= 1LL << j;
                ng:;
            }
        }

        int m1 = m / 2;
        int m2 = m - m1;

        vector dp1(1 << m1, 0);
        vector dp2(1 << m2, 0);

        for (int bit = 0; bit < 1 << m1; ++bit) {
            for (int i = 0; i < m1; ++i) {
                chmax(dp1[bit | 1 << i], dp1[bit]);
                if ((bit & g[i]) == bit) {
                    chmax(dp1[bit | 1 << i], dp1[bit] + 1);
                }
            }
        }
        for (int bit = 0; bit < 1 << m2; ++bit) {
            for (int i = 0; i < m2; ++i) {
                chmax(dp2[bit | 1 << i], dp2[bit]);
                if ((bit & g[m1 + i] >> m1) == bit) {
                    chmax(dp2[bit | 1 << i], dp2[bit] + 1);
                }
            }
        }

        int res = 0;

        for (int bit = 0; bit < 1 << m1; ++bit) {
            int t = (1 << m2) - 1;
            for (int i = 0; i < m1; ++i) {
                if (bit >> i & 1) {
                    t &= g[i] >> m1;
                }
            }
            chmax(res, dp1[bit] + dp2[t]);
        }

        cout << res << '\n';
    }


    return (0);
}
accuracy: 1
time_ms: 1000
memory_kb: 11628
final_rank: 6

code_snippet: #include <bits/extc++.h>

using namespace std;

#define rep(i,n) for(int i=0;i<(n);++i)
#define reps(i,n) for(int i=1;i<=(n);++i)
#define all(x) begin(x),end(x)
#define updiv(a, b) (((a) + (b) - 1) / (b))
using ll = long long;
using ull = unsigned long long;
constexpr int INF  = 0x3f3f3f3f;
constexpr long long LINF = 0x3f3f3f3f3f3f3f3fLL;
constexpr int mod1 = 1000000007;
constexpr int mod2 = 998244353;

template <class Func>
class FixPoint : Func {
public:
    explicit constexpr FixPoint(Func&& f) noexcept : Func(forward<Func>(f)) {}

    template <class... Args>
    constexpr decltype(auto) operator()(Args&&... args) const {
        return Func::operator()(*this, std::forward<Args>(args)...);
    }
};

template <class Func>
static inline constexpr decltype(auto) makeFixPoint(Func&& f) noexcept {
    return FixPoint<Func>{forward<Func>(f)};
}

template <class T, class It = decltype(std::begin(std::declval<T>()))>
inline constexpr auto Indexed(T&& iterable) {
    struct Iterator {
        size_t index;
        It it;
        constexpr bool operator!= (const Iterator& other) const { return it != other.it; }
        constexpr void operator++() { ++index; ++it; }
        constexpr void operator--() { --index; --it; }
        constexpr auto operator*() const { return std::tie(index, *it); }
    };
    struct IterableWrapper {
        T iterable;
        constexpr auto begin() { return Iterator{ 0, std::begin(iterable) }; }
        constexpr auto end() { return Iterator{ std::size(iterable), std::end(iterable) }; }
    };
    return IterableWrapper{ std::forward<T>(iterable) };
}

// {f(i) | i in [begin, left) ∪ (right, rbegin]}
template<class It, class F>
pair<It, reverse_iterator<It> > bsearch(It begin, It end, const F &f) {
    auto rbegin = reverse_iterator(end), rend = reverse_iterator(begin);
    if (begin == end) return make_pair(end, rend);
    It left; reverse_iterator<It> right;
    if (f(*begin)) {
        auto l = begin, r = end;
        while (r - l > 1) {
            auto mid = l + (r - l) / 2;
            if (f(*mid)) l = mid; else r = mid;
        }
        left = r;
    } else left = begin;
    if (f(*rbegin)) {
        auto l = rbegin, r = rend;
        while (r - l > 1) {
            auto mid = l + (r - l) / 2;
            if (f(*mid)) l = mid; else r = mid;
        }
        right = r;
    } else right = rbegin;
    return make_pair(left, right);
}

template<class T, class U> istream& operator>>(istream& is, pair<T, U>& p){ is >> p.first >> p.second; return (is); }
template<class T, class U> ostream& operator<<(ostream& os, pair<T, U>& p){ os << p.first << ' ' << p.second; return (os); }
template<class T> istream& operator>>(istream& is, vector<T>& v){ for (auto &&e : v) is >> e; return (is); }
template<class T> ostream& operator<<(ostream& os, vector<T>& v){ for (auto &&e : v) os << e << ' '; return (os); }

template<class T> inline const T& max(const vector<T> &v) { return *max_element(v.begin(), v.end()); }
template<class T> inline const T& min(const vector<T> &v) { return *min_element(v.begin(), v.end()); }
template<class T> inline T mex(vector<T> v) {
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
    for (T i = 0; i < (T) v.size(); ++i) if (v[i] != i) return i;
    return v.size();
}
template<class T> inline T mex(initializer_list<T> l) { return mex(vector<T>(l)); }

template <class A, class B> inline bool chmax(A &a, const B &b) { return b > a && (a = b, true); }
template <class A, class B> inline bool chmin(A &a, const B &b) { return b < a && (a = b, true); }

template <class T> using max_heap = priority_queue<T>;
template <class T> using min_heap = priority_queue<T, vector<T>, greater<T> >;
template <class A, class B> using umap = unordered_map<A, B>;
template <class T> using uset = unordered_set<T>;

template <class T> using Max_Heap = __gnu_pbds::priority_queue<T, less<T>, __gnu_pbds::rc_binomial_heap_tag>;
template <class T> using Min_Heap = __gnu_pbds::priority_queue<T, greater<T>, __gnu_pbds::rc_binomial_heap_tag>;
template <class T> using Set = __gnu_pbds::tree<T, __gnu_pbds::null_type, less<T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
template <class K, class V> using Umap = __gnu_pbds::gp_hash_table<K, V>;
template <class T> using Rope = __gnu_cxx::rope<T>;

template <class T> void bye(T x){ cout << x << '\n'; exit(0); }

constexpr int dx[] = {1,0,-1,0,1,1,-1,-1,0};
constexpr int dy[] = {0,1,0,-1,1,-1,-1,1,0};

struct XorShift {
private:
    constexpr static double R = 1.0 / 0xffffffff;
    uint64_t x;

    public:
    explicit XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}

    template< typename T = uint64_t >
    inline T get() { // [0, 2^64)
        x ^= x << 7ull;
        x ^= x >> 9ull;
        return x;
    }

    inline uint32_t get(uint32_t r) { // [0, r)
        return ((uint64_t) get< uint32_t >() * r) >> 32ull;
    }

    inline uint32_t get(uint32_t l, uint32_t r) { // [l, r)
        return l + get(r - l);
    }

    inline double probability() { // [0.0, 1.0]
        return get< uint32_t >() * R;
    }
} rnd;

int main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout.setf(ios_base::fixed);
    cout.precision(12);

    int n, m;
    while (cin >> n >> m, n) {

        vector a(n, vector(m, int()));

        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                cin >> a[i][j];
            }
        }

        vector g(m, ll());

        for (int i = 0; i < m; ++i) {
            for (int j = i + 1; j < m; ++j) {
                vector<int> ord(n);
                iota(ord.begin(), ord.end(), 0);
                sort(ord.begin(), ord.end(), [&](int p, int q) {
                    return a[p][i] != a[q][i] ? a[p][i] < a[q][i] : a[p][j] < a[q][j];
                });
                for (int k = 0; k + 1 < n; ++k) {
                    if (a[ord[k]][i] < a[ord[k + 1]][i] && a[ord[k]][j] > a[ord[k + 1]][j]) goto ng;
                }
                g[j] |= 1LL << i;
                g[i] |= 1LL << j;
                ng:;
            }
        }

        vector<int> ord(m);
        iota(ord.begin(), ord.end(), 0);

        int res = 0;

        for (int i = 0; i < 100000; ++i) {
            for (int j = 1; j < m; ++j) {
                int p = rnd.get() % (j + 1);
                swap(ord[p], ord[j]);
            }
            ll mask = 0;
            for (int j = 0; j < m; ++j) {
                for (int k = 0; k < j; ++k) {
                    if ((mask >> ord[k] & 1) && !(g[ord[j]] >> ord[k] & 1)) {
                        goto ng2;
                    }
                }
                mask |= 1LL << ord[j];
                ng2:;
            }
            chmax(res, __builtin_popcountll(mask));
        }

        cout << res << '\n';
    }


    return (0);
}
accuracy: 1
time_ms: 1630
memory_kb: 3676
final_rank: 4

code_snippet: #line 1 "library/Template/template.hpp"
#include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T, typename S = T> S SUM(const vector<T> &a) {
    return accumulate(ALL(a), S(0));
}
template <typename S, typename T = S> S POW(S a, T b) {
    S ret = 1, base = a;
    for (;;) {
        if (b & 1)
            ret *= base;
        b >>= 1;
        if (b == 0)
            break;
        base *= base;
    }
    return ret;
}
template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define debug 1
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define debug 0
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}
#line 2 "library/Utility/fastio.hpp"
#include <unistd.h>
namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf

uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio

using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

/**
 * @brief Fast IO
 */
#line 2 "library/Utility/random.hpp"

namespace Random {
mt19937_64 randgen(chrono::steady_clock::now().time_since_epoch().count());
using u64 = unsigned long long;
u64 get() {
    return randgen();
}
template <typename T> T get(T L) { // [0,L]
    return get() % (L + 1);
}
template <typename T> T get(T L, T R) { // [L,R]
    return get(R - L) + L;
}
double uniform() {
    return double(get(1000000000)) / 1000000000;
}
string str(int n) {
    string ret;
    rep(i, 0, n) ret += get('a', 'z');
    return ret;
}
template <typename Iter> void shuffle(Iter first, Iter last) {
    if (first == last)
        return;
    int len = 1;
    for (auto it = first + 1; it != last; it++) {
        len++;
        int j = get(0, len - 1);
        if (j != len - 1)
            iter_swap(it, first + j);
    }
}
template <typename T> vector<T> select(int n, T L, T R) { // [L,R]
    if (n * 2 >= R - L + 1) {
        vector<T> ret(R - L + 1);
        iota(ALL(ret), L);
        shuffle(ALL(ret));
        ret.resize(n);
        return ret;
    } else {
        unordered_set<T> used;
        vector<T> ret;
        while (SZ(used) < n) {
            T x = get(L, R);
            if (!used.count(x)) {
                used.insert(x);
                ret.push_back(x);
            }
        }
        return ret;
    }
}

void relabel(int n, vector<pair<int, int>> &es) {
    shuffle(ALL(es));
    vector<int> ord(n);
    iota(ALL(ord), 0);
    shuffle(ALL(ord));
    for (auto &[u, v] : es)
        u = ord[u], v = ord[v];
}
template <bool directed, bool multi, bool self>
vector<pair<int, int>> genGraph(int n, int m) {
    vector<pair<int, int>> cand, es;
    rep(u, 0, n) rep(v, 0, n) {
        if (!self and u == v)
            continue;
        if (!directed and u > v)
            continue;
        cand.push_back({u, v});
    }
    if (m == -1)
        m = get(SZ(cand));
    // chmin(m, SZ(cand));
    vector<int> ord;
    if (multi)
        rep(_, 0, m) ord.push_back(get(SZ(cand) - 1));
    else {
        ord = select(m, 0, SZ(cand) - 1);
    }
    for (auto &i : ord)
        es.push_back(cand[i]);
    relabel(n, es);
    return es;
}
vector<pair<int, int>> genTree(int n) {
    vector<pair<int, int>> es;
    rep(i, 1, n) es.push_back({get(i - 1), i});
    relabel(n, es);
    return es;
}
}; // namespace Random

/**
 * @brief Random
 */
#line 4 "sol.cpp"

#line 3 "library/Graph/maxindependentset.hpp"

struct MaxIndependentSet {
    const int n;
    vector<ll> es;
    MaxIndependentSet(int _n) : n(_n), es(n) {}
    void add_edge(int u, int v) {
        es[u] |= 1LL << v;
        es[v] |= 1LL << u;
    }
    pair<ll, ll> run(vector<ll> &cost, int _rot = 1e6) {
        vector<int> ord(n);
        iota(ALL(ord), 0);
        ll ret = 0;
        ll cur = 0;
        rep(_, 0, _rot) {
            Random::shuffle(ALL(ord));
            ll add = 0;
            ll used = 0;
            for (auto &v : ord)
                if (!(used & es[v])) {
                    used |= (1LL << v);
                    add += cost[v];
                }
            if (chmax(ret, add))
                cur = used;
        }
        return {ret, cur};
    }
};

/**
 * @brief Maximum Independent Set
 */
#line 6 "sol.cpp"

int main() {
    for (;;) {
        int n, m;
        read(n, m);
        if (n == 0 or m == 0)
            break;
        vector a(n, vector<int>(m));
        read(a);

        MaxIndependentSet buf(m);
        rep(i, 0, m) rep(j, 0, m) if (i < j) {
            using P = pair<int, int>;
            vector<P> b;
            rep(k, 0, n) {
                b.push_back({a[k][i], a[k][j]});
            }
            sort(ALL(b));
            bool ch = 0;
            rep(k, 0, n - 1) if (b[k].second > b[k + 1].second) {
                ch = 1;
                break;
            }
            if (ch) {
                show(i, j);
                buf.add_edge(i, j);
            }
        }
        vector<ll> cost(m, 1);
        auto [ret, _] = buf.run(cost, 1e5);
        show(ret);
        print(ret);
    }
    return 0;
}
accuracy: 1
time_ms: 1110
memory_kb: 3776
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;

vector<int> maximum_independent_set(const vector<vector<int>> &g) {
    int n = g.size();
    vector<int> deg(n), used(n);
    vector<bool> vis(n), ans(n);
    for (int i = 0; i < n; i++) deg[i] = g[i].size();
    int cur = 0, cnt = 0, alive = n;
    auto dfs = [&](const auto &dfs) -> void {
        if (cnt + alive <= cur) return;
        int u = -1;
        for (int i = 0; i < n; i++) {
            if (!vis[i] && !used[i]) {
                if (deg[i] <= 1) {
                    u = i;
                    break;
                }
                if (u < 0 || deg[u] < deg[i]) u = i;
            }
        }
        if (u < 0) return;
        if (deg[u] != 1) {
            used[u] = 1;
            alive--;
            for (int v : g[u]) deg[v]--;
            dfs(dfs);
            used[u] = 0;
            alive++;
            for (int v : g[u]) deg[v]++;
        }
        vis[u] = true;
        alive--;
        for (int v : g[u]) {
            if (!used[v]++) alive--;
        }
        cnt++;
        if (cur < cnt) {
            ans = vis;
            cur = cnt;
        }
        dfs(dfs);
        vis[u] = 0;
        alive++;
        for (int v : g[u]) {
            if (!--used[v]) alive++;
        }
        cnt--;
    };
    dfs(dfs);
    vector<int> res;
    for (int i = 0; i < n; i++) {
        if (ans[i]) res.push_back(i);
    }
    return res;
}

bool solve() {
    int N, M;
    cin >> N >> M;
    if (N == 0 && M == 0) return false;
    vector<vector<int>> A(N, vector<int>(M));
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) cin >> A[i][j];
    }
    vector<vector<int>> G(M);
    for (int p = 0; p < M; p++) {
        for (int q = p + 1; q < M; q++) {
            bool ok = false;
            for (int i = 0; i < N; i++) {
                for (int j = i + 1; j < N; j++) {
                    if (A[i][p] > A[j][p] && A[i][q] < A[j][q]) ok = true;
                    if (A[i][p] < A[j][p] && A[i][q] > A[j][q]) ok = true;
                }
            }
            if (ok) {
                G[p].push_back(q);
                G[q].push_back(p);
            }
        }
    }
    cout << maximum_independent_set(G).size() << endl;
    return true;
}

int main() {
    while (solve()) {}
}
accuracy: 1
time_ms: 4260
memory_kb: 3712
final_rank: 9

code_snippet: #pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

// #ifndef ONLINE_JUDGE
// #define _GLIBCXX_DEBUG // 配列外参照のエラー
// #endif

// スタンダードライブラリ
#include <bits/stdc++.h>
using namespace std;

// 型関連
using ll = long long;
using lint = long long;
using pll = pair<ll, ll>;
using plll = tuple<ll, ll, ll>;
using pii = pair<int, int>;
using piii = tuple<ll, ll, ll>;
template <class T> using prique = priority_queue<T>;

// 型定数
constexpr ll mod = 998244353;
constexpr ll MOD = 1000000007;
int INF32 = 2e9;
ll INF64 = 9e18;
#define endl '\n';

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

/////////////////////////// print関連
template <typename T> void print(vector<T> A);
void print();
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail);
void print(string S);
template <typename T> void print(vector<vector<T>> &F);

inline void Yes(bool f);

int maximum_clique(vector<vector<bool>> &G) {
    int N = G.size();
    if (N == 1) {
        return 1;
    }
    int NL = N / 2;
    int NR = N - NL;

    vector<int> dp(1 << NR, 0);
    for (int S = 0; S < (1 << NL); S++) {
        vector<int> bits;
        for (int i = 0; i < NL; i++) {
            if (S & (1 << i)) {
                bits.push_back(i);
            }
        }
        bool ok = true;
        for (int i = 0; i < bits.size(); i++) {
            for (int j = i + 1; j < bits.size(); j++) {
                if (G[bits[i]][bits[j]] == false) {
                    ok = false;
                    goto b1;
                }
            }
        }
    b1:;
        if (ok == false) {
            continue;
        }

        int SB = 0;
        for (int i : bits) {
            for (int j = 0; j < NR; j++) {
                if (G[i][j + NL] == false) {
                    SB |= (1<<(j));
                }
            }
        }
        SB = ((1 << NR) - 1) ^ SB;
        dp[SB]=max(dp[SB],(int)bits.size());
    }
    for (int S = (1 << NR)-1; S>=0; S--) {
        for (int i = 0; i < NR; i++) {
            if (S & (1 << i)) {
                dp[S - (1<<i)]=max(dp[S-(1<<i)], dp[S]);
            }
        }
    }
    int ret = 1;
    for (int S = 0; S < (1 << NR); S++) {
        vector<int> bits;
        for (int i = 0; i < NR; i++) {
            if (S & (1 << i)) {
                bits.push_back(i);
            }
        }
        bool ok=true;
        for (int i = 0; i < bits.size(); i++) {
            for (int j = i + 1; j < bits.size(); j++) {
                if (G[bits[i] + NL][bits[j] + NL] == false) {
                    ok = false;
                    goto b2;
                }
            }
        }
    b2:;
        if (ok == false) {
            continue;
        }

        ret=max(ret,(int)bits.size()+dp[S]);
    }
    return ret;

}

///////////////////ここから//////////////////////
bool solve() {
    int N, M;
    cin >> N >> M;
    if (N == 0) {
        return false;
    }
    vector<vector<int>> Score(M, vector<int>(N));
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> Score[j][i];
        }
    }

    vector<vector<bool>> G(M, vector<bool>(M, false));
    for (int i = 0; i < M; i++) {
        for (int j = i + 1; j < M; j++) {
            bool ok = true;
            vector<pii> VP(N);
            for (int k = 0; k < N; k++) {
                VP[k] = {Score[i][k], Score[j][k]};
            }
            sort(VP.begin(), VP.end());
            for (int k = 0; k < N - 1; k++) {
                if (VP[k + 1].first > VP[k].first &&
                    VP[k + 1].second < VP[k].second) {
                    ok = false;
                }
            }

            if (ok) {
                G[i][j] = true;
                G[j][i] = true;
            }
        }
    }
    // for (auto g : G) {
    //     print(g);
    // }
    print(maximum_clique(G));

    return true;
}

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    while (solve())
        ;
}

////////////////////print/////////////////////////
// 1次元ベクトルを出力する
template <typename T> void print(vector<T> A) {
    if (A.size() == 0) {
        cout<<endl;
        return;
    }
    for (size_t i = 0; i < A.size() - 1; i++) {
        cout << A[i] << ' ';
    }
    cout << A[A.size() - 1] << endl;
    return;
}

// 2次元ベクトルを出力する
template <typename T> void print(vector<vector<T>> &F) {
    for (size_t i = 0; i < F.size(); i++) {
        for (size_t j = 0; j < F[i].size(); j++) {
            cout << F[i][j];
            if (j < F[i].size() - 1) {
                cout << ' ';
            }
        }
        cout << endl;
    }
}

// 空白行を出力するprint
void print() { cout << endl; }

// 数値・文字列を空白区切りで出力する. print(a,b)など
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    cout << head;
    if (sizeof...(tail) != 0)
        cout << " ";
    print(forward<Tail>(tail)...);
    //cout<<endl;
}

void print(string S) { cout << S << endl; }

//////////////出力関連

inline void Yes(bool f) {
    if (f) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
}
accuracy: 1
time_ms: 2900
memory_kb: 8568
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define all(...) std::begin(__VA_ARGS__), std::end(__VA_ARGS__)
#define rall(...) std::rbegin(__VA_ARGS__), std::rend(__VA_ARGS__)
#define OVERLOAD_REP(_1, _2, _3, _4, name, ...) name
#define REP1(n) for(ll i=0;i<(n);i++)
#define REP2(i, n) for (ll i=0;i<(n);i++)
#define REP3(i, a, n) for (ll i=a;i<(n);i++)
#define REP4(i, a, b, n) for(ll i=a;i<(n);i+=b)
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP4, REP3, REP2, REP1)(__VA_ARGS__)
#define OVERLOAD_RREP(_1, _2, _3, _4, name, ...) name
#define RREP1(n) for(ll i=(n)-1;i>=0;i--)
#define RREP2(i, n) for(ll i=(n)-1;i>=0;i--)
#define RREP3(i, a, n) for(ll i=(n)-1;i>=(a);i--)
#define RREP4(i, a, b, n) for(ll i=(n)-1;i>=(a);i-=(b))
#define rrep(...) OVERLOAD_RREP(__VA_ARGS__, RREP4, RREP3, RREP2, RREP1)(__VA_ARGS__)
#define uniq(a) sort(all(a));a.erase(unique(all(a)),end(a))
#define len(n) (long long)(n).size()
using ll = long long;
using ld = long double;
using ull = unsigned long long;
using vi = vector<int>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vs = vector<string>;
using vvs = vector<vs>;
using vvvs = vector<vvs>;
using vld = vector<ld>;
using vvld = vector<vld>;
using vvvld = vector<vvld>;
using vc = vector<char>;
using vvc = vector<vc>;
using vvvc = vector<vvc>;
using pll = pair<ll,ll>;
using vpll = vector<pll>;
using vvpll = vector<vpll>;

ll intpow(ll a,ll b){
    ll ans = 1;
    while (b){
        if (b & 1){
            ans *= a;
        }
        a *= a;
        b /= 2;
    }
    return ans;
}
ll modpow(ll a,ll b,ll c){
    ll ans = 1;
    while (b){
        if (b & 1){
            ans *= a;
            ans %= c;
        }
        a *= a;
        a %= c;
        b /= 2;
    }
    return ans;
}

template<class... T>
void input(T&... a){
    (cin >> ... >> a);
}

#define INT(...) int __VA_ARGS__; input(__VA_ARGS__)
#define LL(...) ll __VA_ARGS__; input(__VA_ARGS__)
#define ULL(...) ull __VA_ARGS__; input(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; input(__VA_ARGS__)
#define STR(...) string __VA_ARGS__; input(__VA_ARGS__)
#define CHA(...) char __VA_ARGS__; input(__VA_ARGS__)
#define VLL(name,length) vll name(length);rep(i,length){cin >> name[i];}
#define VVLL(name,h,w) vvll name(h,vll(w));rep(i,h)rep(j,w){cin >> name[i][j];}
#define VVVLL(name,a,b,c) vvvll name(a,vvll(b,vll(c)));rep(i,a)rep(j,b)rep(k,c){cin >> name[i][j][k];}
#define VI(name,length) vi name(length);rep(i,length){cin >> name[i];}
#define VVI(name,h,w) vvi name(h,vi(w));rep(i,h)rep(j,w){cin >> name[i][j];}
#define VVVI(name,a,b,c) vvvi name(a,vvll(b,vi(c)));rep(i,a)rep(j,b)rep(k,c){cin >> name[i][j][k];}
#define VLD(name,length) vld name(length);rep(i,length){cin >> name[i];}
#define VVLD(name,h,w) vvld name(h,vld(w));rep(i,h)rep(j,w){cin >> name[i][j];}
#define VVVLD(name,a,b,c) vvvld name(a,vvld(b,vld(c)));rep(i,a)rep(j,b)rep(k,c){cin >> name[i][j][k];}
#define VC(name,length) vc name(length);rep(i,length){cin >> name[i];}
#define VVC(name,h,w) vvc name(h,vc(w));rep(i,h)rep(j,w){cin >> name[i][j];}
#define VVVC(name,a,b,c) vvvc name(a,vvc(b,vc(c)));rep(i,a)rep(j,b)rep(k,c){cin >> name[i][j][k];}
#define VS(name,length) vs name(length);rep(i,length){cin >> name[i];}
#define VVS(name,h,w) vvs name(h,vs(w));rep(i,h)rep(j,w){cin >> name[i][j];}
#define VVVS(name,a,b,c) vvvs name(a,vvs(b,vs(c)));rep(i,a)rep(j,b)rep(k,c){cin >> name[i][j][k];}
#define PLL(name) pll name;cin>>name.first>>name.second;
#define VPLL(name,length) vpll name(length);rep(i,length){cin>>name[i].first>>name[i].second;}

void print(){cout << "\n";}

template <typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1, T2>& p) {
    os << "(" << p.first << ", " << p.second << ")";
    return os;
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) {
    os << "[";
    for (size_t i = 0; i < vec.size(); ++i) {
        os << vec[i];
        if (i + 1 < vec.size()) os << ", ";
    }
    os << "]";
    return os;
}

template <typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::vector<std::pair<T1, T2>>& a) {
    os << "[";
    for (size_t j = 0; j < a.size(); ++j) {
        os << "(" << a[j].first << ", " << a[j].second << ")";
		if (j + 1 < a.size()) os << ", ";
    }
	os << "]";
    return os;
}

template <typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::vector<std::vector<std::pair<T1, T2>>>& mat) {
	os << "[";
    for (size_t i = 0; i < mat.size(); ++i) {
		os << "[";
        for (size_t j = 0; j < mat[i].size(); ++j) {
            os << "(" << mat[i][j].first << ", " << mat[i][j].second << ")";
			if (j + 1 < mat[i].size()) os << ", ";
        }
		os << "]";
		if (i + 1 < mat.size()) os << ", ";
    }
	os << "]";
    return os;
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::set<T>& s) {
    os << "{";
    bool first = true;
    for (const auto& x : s) {
        if (!first) os << ", ";
        os << x;
        first = false;
    }
    os << "}";
    return os;
}

template <typename K, typename V>
std::ostream& operator<<(std::ostream& os, const std::map<K, V>& m) {
    os << "{";
    bool first = true;
    for (const auto& [key, val] : m) {
        if (!first) os << ", ";
        os << key << ": " << val;
        first = false;
    }
    os << "}";
    return os;
}

template<class T, class... Ts>
void print(const T& a, const Ts&... b){cout << a;(cout << ... << (cout << ' ', b));cout << '\n';}

void write(){cout << "\n";}
template<class T, class... Ts>
void write(const T& a, const Ts&... b){cout << a;(cout << ... << (cout << ' ', b));cout << '\n';}
void write(vll x){rep(i,len(x)){cout << x[i];if(i!=len(x)-1){cout << " ";}else{cout << '\n';}}}
void write(vvll x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j];if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}
void write(vi x){rep(i,len(x)){cout << x[i];if(i!=len(x)-1){cout << " ";}else{cout << '\n';}}}
void write(vvi x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j];if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}
void write(vvvi x){rep(i,len(x))rep(j,len(x[i]))rep(k,len(x[i][j])){cout << x[i][j][k];if(k!=len(x[i][j])-1){cout << " ";}else if(j!=len(x[i])-1){cout << " | ";}else{cout << '\n';}}}
void write(vld x){rep(i,len(x)){cout << x[i];if(i!=len(x)-1){cout << " ";}else{cout << '\n';}}}
void write(vvld x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j];if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}
void write(vvvld x){rep(i,len(x))rep(j,len(x[i]))rep(k,len(x[i][j])){cout << x[i][j][k];if(k!=len(x[i][j])-1){cout << " ";}else if(j!=len(x[i])-1){cout << " | ";}else{cout << '\n';}}}
void write(vc x){rep(i,len(x)){cout << x[i];if(i!=len(x)-1){cout << " ";}else{cout << '\n';}}}
void write(vvc x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j];if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}
void write(vvvc x){rep(i,len(x))rep(j,len(x[i]))rep(k,len(x[i][j])){cout << x[i][j][k];if(k!=len(x[i][j])-1){cout << " ";}else if(j!=len(x[i])-1){cout << " | ";}else{cout << '\n';}}}
void write(vs x){rep(i,len(x)){cout << x[i];if(i!=len(x)-1){cout << " ";}else{cout << '\n';}}}
void write(vvs x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j];if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}
void write(vvvs x){rep(i,len(x))rep(j,len(x[i]))rep(k,len(x[i][j])){cout << x[i][j][k];if(k!=len(x[i][j])-1){cout << " ";}else if(j!=len(x[i])-1){cout << " | ";}else{cout << '\n';}}}
void write(pll x){cout << x.first << ' ' << x.second << '\n';}
void write(vpll x){rep(i,len(x)){cout << x[i].first << ' ' << x[i].second << '\n';}}
void write(vvpll x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j].first << ' ' << x[i][j].second;if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}

template <typename T>
T sum(const std::vector<T>& v) {
    return std::accumulate(v.begin(), v.end(), T(0));
}

template<class T> bool chmin(T& a, const T& b){ if(a > b){ a = b; return 1; } return 0; }
template<class T> bool chmax(T& a, const T& b){ if(a < b){ a = b; return 1; } return 0; }
template<class T, class U> bool chmin(T& a, const U& b){ if(a > T(b)){ a = b; return 1; } return 0; }
template<class T, class U> bool chmax(T& a, const U& b){ if(a < T(b)){ a = b; return 1; } return 0; }



int main(){
	ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
    while(1){
        LL(n,m);
        if(n == 0 && m == 0){return 0;}
        VVLL(a,n,m);
        vvll e(m,vll(m,0));
        rep(i,m){
            e[i][i] = 1;
            rep(j,i+1,m){
                sort(all(a),[&](vll a,vll b){return make_pair(a[i],a[j]) < make_pair(b[i],b[j]);});
                ll cnt = 0;
                rep(k,n-1){
                    if(a[k][j] > a[k+1][j]){
                        cnt = 1;
                        break;
                    }
                }
                if(cnt == 1){
                    e[i][j] = 1;
                    e[j][i] = 1;
                }
            }
        }


        ll b = m / 2;
        ll l = b;
        ll r = m - b;
        vll dp1(1<<l,0);
        rep(i,(1<<l)){
            ll v = 1;
            rep(j,l){
                rep(k,j+1,l){
                    if(((i >> j) & 1 == 1) && ((i >> k) & 1) == 1 && e[j][k] == 1){
                        v = 0;
                        break;
                    }
                }
            }
            dp1[i] = v;
        }

        vll dp2(1<<r,0);
        rep(i,(1<<r)){
            ll v = 1;
            rep(j,r){
                rep(k,j+1,r){
                    if(((i >> j) & 1 == 1) && (((i >> k) & 1) == 1) && (e[j+l][k+l] == 1)){
                        v = 0;
                        break;
                    }
                }
            }
            if(v == 0){continue;}
            dp2[i] = __builtin_popcountll(i);
        }
        
        
        rep(i,r){
            rep(j,(1<<r)){
                if(((j >> i) & 1) == 0){
                    chmax(dp2[j | (1LL << i)] , dp2[j]);
                }
            }
        }

        ll ans = 0;
        rep(i,(1<<l)){
            if(dp1[i] == 0){continue;}
            ll v = (1 << r)-1;
            rep(j,l){
                if(((i >> j) & 1) == 1){
                    rep(k,r){
                        if(e[j][k + l] == 1 && ((v >> k) & 1) == 1){
                            v ^= (1 << k);
                        }
                    }
                }
            }
            //print(i,v);
            ans = max(ans, __builtin_popcountll(i) + dp2[v]);
        }
        print(ans);

    }
    
}
accuracy: 1
time_ms: 4240
memory_kb: 20156
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define all(v) (v).begin(),(v).end()
#define pb(a) push_back(a)
#define rep(i, n) for(int i=0;i<n;i++)
#define foa(e, v) for(auto&& e : v)
using ll = long long;
const ll MOD7 = 1000000007, MOD998 = 998244353, INF = (1LL << 60);
#define dout(a) cout<<fixed<<setprecision(10)<<a<<endl;
void chmax(ll &a, ll b) { a = max(a, b); }
void chmax(int &a, int b) { a = max(a, b); }
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    ll n, m; cin >> n >> m;
    while(n) {
        vector a(n, vector(m, 0));
        rep(i, n) rep(j, m) cin >> a[i][j];
        vector<ll> bit(m);
        rep(i, m) rep(j, m) {
            vector<pair<int, int>> v;
            rep(k, n) {
                v.push_back({a[k][i], a[k][j]});
            }
            sort(all(v));
            bool ng = 0;
            rep(k, n - 1) {
                if(v[k].second > v[k + 1].second) ng = 1;
            }
            if(!ng) bit[i] |= 1LL << j;
        }
        int x = m / 2;
        vector<ll> dp(1 << x, 0LL);
        rep(b, 1 << x) {
            ll sum = b;
            rep(k, x) {
                if(b >> k & 1) sum &= bit[k];
            }
            if(sum == b) dp[b] = __builtin_popcount(b);
        }
        rep(b, 1 << x) {
            rep(k, x) {
                if(b >> k & 1) continue;
                chmax(dp[b | (1 << k)], dp[b]);
            }
        }
        int M = m - x;
        int ans = 0;
        rep(b, 1 << M) {
            ll sum = (1LL << m) - 1;
            rep(k, M) {
                if(b >> k & 1) {
                    sum &= bit[k + x];
                }
            }
            bool ng = 0;
            rep(k, M) {
                if((b >> k & 1) and !(sum >> (k + x) & 1)) ng = 1;
            }
            if(!ng) chmax(ans, dp[sum & ((1 << x) - 1)] + __builtin_popcount(b));
        }
        cout << ans << endl;
        cin >> n >> m;
    }
    return 0;
}
accuracy: 1
time_ms: 1360
memory_kb: 13344
final_rank: 11

code_snippet: //#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,n) for (ll i=0;i<(ll)n;i++)
#define rrep(i,n) for (ll i=n-1;i>=(ll)0;i--)
#define loop(i,m,n) for(ll i=m;i<=(ll)n;i++)
#define rloop(i,m,n) for(ll i=m;i>=(ll)n;i--)
#define vl vector<long long>
#define vvl vector<vector<long long>>
#define vdbg(a) rep(ii,a.size()){cout<<a[ii]<<" ";}cout<<endl;
#define vvdbg(a) rep(ii,a.size()){rep(jj,a[ii].size()){cout<<a[ii][jj]<<" ";}cout<<endl;}
#define setdbg(a) for(const auto & ii:a){cout<<ii<<" ";}cout<<endl;
#define YES cout<<"Yes"<<endl;return 0;
#define NO cout<<"No"<<endl;return 0;
#define inf 4000000000000000000LL
#define mod 998244353LL
//#define mod 1000000007LL
random_device rnd;// 非決定的な乱数生成器
mt19937 mt(rnd());// メルセンヌ・ツイスタの32ビット版、引数は初期シード


//#include<boost/multiprecision/cpp_int.hpp>
//#define bbi boost::multiprecision::cpp_int

//#include<atcoder/lazysegtree>

//√の値が整数かを調べる
bool isSqrt(ll n) {
	if (n < 0) return false;
	ll sqrtN = static_cast<ll>(sqrt(n));
	return sqrtN * sqrtN == n;
}

//整数同士の累乗の計算をする。
ll power(ll A, ll B) {
	ll result = 1;
	for (ll i=0;i<B;i++){
		result *= A;
	}
	return result;
}

//素因数分解
vector<ll> makePrime(ll n){
	vector<ll> factors;
	while (n % 2 == 0) {
		factors.push_back(2);
		n /= 2;
	}
	for (ll i=3; i*i<=n;i+=2) {
		while (n%i == 0) {
			factors.push_back(i);
			n /= i;
		}
	}
	if (n > 2) {
		factors.push_back(n);
	}
	return factors;
}

//map形式で、nを素因数分解した値を返す
map<ll,ll> makeMapPrime(ll n){
	map<ll,ll> factors;
	while (n % 2 == 0) {
		factors[2]++;
		n /= 2;
	}
	for (ll i=3; i*i<=n;i+=2) {
		while (n%i == 0) {
			factors[i]++;
			n /= i;
		}
	}
	if (n > 2) {
		factors[n]++;
	}
	return factors;
}

// nのk乗をmodで割った余りを計算
ll power_mod(ll n, ll k){
	long long result = 1;
	while (k > 0){
		if ((k&1) ==1)result=(result*n)%mod;
		n=n*n%mod;
		k >>= 1;
	}
	return result;
}

//mod mにおけるaの逆元を計算
ll modinv(ll a, ll m) {
	ll b = m, u = 1, v = 0;
	while (b) {
		ll t = a / b;
		a -= t * b; swap(a, b);
		u -= t * v; swap(u, v);
	}
	u %= m; 
	if (u < 0) u += m;
	return u;
}

//場合の数 nCr を求める
ll ncr(ll n,ll r) {
	if(n<r)return 0;
	vvl dp(n+1,vl(r+1));
	rep (i,n+1)dp[i][0] = 1;
	rep (i,r+1)dp[i][i] = 1;
	loop (i,1,n){
		loop (j,1,min((ll)i-1,r)) {
			//nCr= n-1Cr-1 + n-1Cr
			dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
		}
	}
	return dp[n][r];
}

//受け取った文字列を、第2引数が0なら全て小文字に、1なら大文字に変換する関数
string cnvString(const string &str, int mode) {
	string result = str;
	if (mode == 0) {
		// 小文字に変換
		for (char &c : result) {
			c = tolower(c);
		}
	} else if (mode == 1) {
		// 大文字に変換
		for (char &c : result) {
			c = toupper(c);
		}
	}
	return result;
}

//第一引数で受け取った数を、第二引数で受け取った数の進数と見做して、第三引数の進数へ変換する。
string cnvBase(const string &str, ll from_base, ll to_base) {
	ll num = 0;
	//小文字があったら大文字に変換
	string num_str=cnvString(str,1);
	// 数値を10進数に変換
	for (char digit : num_str) {
		num = num * from_base + (isdigit(digit) ? digit - '0' : digit - 'A' + 10);
	}
	string result;
	// 数値を目的の基数に変換
	while (num > 0) {
		ll remainder = num % to_base;
		result.push_back(remainder < 10 ? remainder + '0' : remainder - 10 + 'A');
		num /= to_base;
	}
	// 結果を逆順にして返す
	reverse(result.begin(), result.end());
	return result.empty() ? "0" : result;
}

//底がaの対数xを計算。ただし小数点は繰り上げ。
ll logax(ll a, ll x){
	if(x<=1)return 0;
	ll result = 1;
	ll power = 1;
	while (power < (x+a-1) / a){
		power *= a;
		result++;
	}
	return result;
}

//第一引数を第二引数で割った余りを計算、割る数はint範囲
ll bigmd(const string &num, int md) {
	ll ans = 0;
	ll SIZ = 9; //9桁のチャンク
	ll base = 1000000000;//SIZ個の0
	rep(i,(num.size()-1)/SIZ+1){
		ll chunk = 0;
		ll l = i*SIZ;
		ll r = min((ll)num.size(),l+SIZ);
		if(r!=num.size()){
			ans = (ans*base+stoll(num.substr(l,r-l)))%md;
		}else{
			rep(i,r-l)ans*=10;
			ans=(ans+stoll(num.substr(l,r-l)))%md;
		}
	}
	return ans;
}

//受け取った2次元文字の外側に、文字pをコーティングする。
vector<string> pad(vector<string> &s,char p){
	ll h=s.size();
	ll w=s[0].size();
	vector<string> res(h+2,string(w+2,p));
	rep(i,h)rep(j,w)res[i+1][j+1]=s[i][j];
	return res;
}

//ax+by=cの整数解を得る ただし、cはgcd(a,b)の倍数でない場合、0,0になる
pair<ll,ll> ex_euclid(ll a,ll b,ll c){
	if(a<0||b<0||c<0){
		pair<ll,ll>ans=ex_euclid(abs(a),abs(b),abs(c));
		if(a<0)ans.first*=-1;
		if(b<0)ans.second*=-1;
		if(c<0)ans.first*=-1,ans.second*=-1;
		return ans;
	}
	if(c!=1){
		ll d=gcd(a,b);
		if(c%d!=0)return make_pair(0,0);
		pair<ll,ll>ans = ex_euclid(a/d,b/d,1);
		ans.first*=c/d;
		ans.second*=c/d;
		return ans;
	}
	if(a<b){
		pair<ll,ll>ans=ex_euclid(b,a,c);
		swap(ans.first,ans.second);
		return ans;
	}
	if(a==1&&b==0)return make_pair(1,0);
	else if(b==0) return make_pair(0,0);
	ll x,y;
	tie(x,y)=ex_euclid(b,a%b,c);
	pair<ll,ll> ans=make_pair(y,x-(a/b)*y);
	return ans;
}

//オイラーのトーシェント関数。N以下のNと互いに素な物の数を返す。
ll euler(ll n){
	unordered_map<ll,ll> factors;
	ll tmp=n;
	while (tmp % 2 == 0) {
		factors[2]++;
		tmp /= 2;
	}
	for (ll i=3; i*i<=tmp;i+=2) {
		while (tmp%i == 0) {
			factors[i]++;
			tmp/= i;
		}
	}
	if (tmp > 2)factors[tmp]++;
	ll ans=1;
	for(const auto & val:factors){
		ans*=power(val.first,val.second-1)*(val.first-1);
	}
	return ans;
}

// Union-Find
struct UnionFind {
	vector<int> par, siz;
	UnionFind(int n) : par(n, -1) , siz(n, 1) { }
	// 根を求める
	int root(int x) {
		if (par[x] == -1) return x;
		else return par[x] = root(par[x]);
	}
	// x と y が同じグループに属するかどうか (根が一致するかどうか)
	bool issame(int x, int y) {
		return root(x) == root(y);
	}
	// x を含むグループと y を含むグループとを併合する
	bool unite(int x, int y) {
		x = root(x), y = root(y);
		if (x == y) return false;
		if (siz[x] < siz[y]) swap(x, y);
		par[y] = x;
		siz[x] += siz[y];
		return true;
	}
	// x を含むグループのサイズ
	int size(int x) {
		return siz[root(x)];
	}
};

//重み付きUF
struct PotentialUnionFind {
	ll n;
	vl par, siz, pot;
	PotentialUnionFind(ll N) : par(N,-1) , siz(N,1) , pot(N,0){n=N;}
	// 根を求める
	ll root(ll x) {
		if (par[x] == -1) return x;
		ll tmp = root(par[x]);
		pot[x] += pot[par[x]];
		par[x] = tmp;
		return par[x];
	}
	// x と y が同じグループに属するかどうか (根が一致するかどうか)
	bool issame(ll x, ll y) {
		return root(x) == root(y);
	}
	//x よりいくつ大きい所に y があるか。根が一致しない場合は"0"
	ll potential(ll x,ll y){
		if(root(x) != root(y)) return 0;
		else return pot[y]-pot[x];
	}
	//x より w だけ大きい状態として y を併合。
	bool unite(ll x, ll y, ll w) {
		ll rx = root(x),ry = root(y);
		if (rx == ry) return false;
		w += pot[x]-pot[y];
		if (siz[rx] < siz[ry]) swap(rx, ry),w*=-1;
		par[ry] = rx;
		siz[rx] += siz[ry];
		siz[ry] = 0;
		pot[ry] = w;
		return true;
	}
	// x を含むグループのサイズ
	ll size(ll x) {
		return siz[root(x)];
	}
	//小さい順にUnionFindグラフを調整、O(n log n)
	void regulation(){
		vvl r(n);
		rep(i,n)r[root(i)].push_back(i);
		rep(i,n){
			if(r[i].size()==0)continue;
			ll mn = i;
			rep(j,r[i].size())if(pot[mn]>pot[r[i][j]])mn=r[i][j];
			siz[mn]=siz[i];
			siz[i]=0;
			ll tmp = pot[mn];
			rep(j,r[i].size()){
				pot[r[i][j]]-=tmp;
				par[r[i][j]] = mn;
			}
			par[mn]=-1;
		}
	}
	void debug(){
		rep(i,n)cout<<setw(4)<<left<<par[i]<<" ";
		cout<<endl;
		rep(i,n)cout<<setw(4)<<left<<pot[i]<<" ";
		cout<<endl;
	}
};

//分離可能UnionFind、経路圧縮をしない。
struct CuttingFind{
	vector<int> par, siz;
	CuttingFind(int n) : par(n, -1) , siz(n, 1) { }
	// 根を求める
	int root(int x) {
		if (par[x] == -1) return x;
		else return root(par[x]);
	}
	// x と y が同じグループに属するかどうか (根が一致するかどうか)
	bool issame(int x, int y) {
		return root(x) == root(y);
	}
	//根x と 根y のグループを併合する(お互い根ではない時、falseで何もしない)
	bool unite(int x, int y) {
		if (issame(x,y) || par[x] != -1 || par[y] != -1) {
			cout<<"error"<<endl;
			return false;
		}
		if (siz[x] < siz[y]) swap(x, y);
		par[y] = x;
		siz[x] += siz[y];
		return true;
	}
	//根の側から、その直系の子供を分離する。片方が根でもう片方が直系の子でなければならない。
	bool separate(int x,int y){
		if(par[y]==-1)swap(x,y);
		if(par[y]!=x||par[x]!=-1){
			cout<<"error2"<<endl;
			return false;
		}
		siz[x] -= siz[y];
		par[y]=-1;
		return true;
	}
	// x を含むグループのサイズを求める
	int size(int x) {
		return siz[root(x)];
	}
};
//セグ木,乗せる値の型が必要
template<typename T>
struct SegTree{
	ll size;
	ll tall;
	vector<T> data;
	function<T(T,T)> p;
	//セグ木に乗せる値の初期値をa配列にし、putの関数をセグ木に乗せる、dをデフォルト値に。
	SegTree(vector<T> a,function<T(T,T)> put,T d) : data(power(2,logax(2,a.size())+1)) {
		size = data.size()/2;
		tall=logax(2,size)+1;
		p=put;
		ll tmp=size;
		data = vector<T>(size*2,d);
		while(tmp!=0){
			if(tmp==size)rep(i,a.size())data[tmp+i]=a[i];
			else rep(i,tmp) data[tmp+i]=p(data[2*(tmp+i)],data[2*(tmp+i)+1]);
			tmp/=2;
		}
	}
	//更新、t番目の値をxにする。
	void update(ll t,T x){
		t+=size;
		while(t!=0){
			if(t>=size)data[t]=x;
			else data[t]=p(data[2*t],data[2*t+1]);
			t/=2;
		}
	}
	//取得、l~r区間内の評価値を取得する。
	T get(ll l,ll r){
		//lとrが範囲外なら範囲内に正す
		l=max(0LL,l);
		r=min(r,size-1);
		r++;
		T ans=data[0];
		ll pos=l+size;
		ll wid=1;
		//出来る限り上に上げきる。
		while(l+(wid*2)<=r){
			while(l%(wid*2)==0&&l+(wid*2)<=r)pos/=2,wid*=2;
			ans=p(ans,data[pos]);
			pos++;
			l+=wid;
		}
		//上げ終わったので今度は下げる
		while(l!=r){
			while(l+wid>r)pos*=2,wid/=2;
			ans=p(ans,data[pos]);
			pos++;
			l+=wid;
		}
		return ans;
	}
	//セグ木デバッグ用、丸ごと出力
	void print(){
		rep(i,size)cout<<setw(7)<<left<<i;
		cout<<endl;
		ll pos=size;
		rep(i,tall){
			rep(j,size){
				if(j%power(2,i)==0)cout<<setw(7)<<left<<data[pos],pos++;
				else cout<<"       ";
			}
			pos/=4;
			cout<<endl;
		}
	}
};

//グリッド問題等用
vl dx={1,0,-1,0};
vl dy={0,1,0,-1};




ll solve(){
	ll n,m;
	cin>>n>>m;
	if(n==0&&m==0){return 1;}
	vvl g=vvl(m);
	vvl a(n,vl(m));
	rep(i,n)rep(j,m)cin>>a[i][j];
	
	rep(i,m)rep(j,i){
		vector<pair<ll,ll>> tmp(n);
		rep(k,n)tmp[k]={a[k][i],a[k][j]};
		sort(tmp.begin(),tmp.end());
		bool f=false;
		rep(k,n-1)if(tmp[k].second>tmp[k+1].second)f=true;
		if(f){
			g[i].push_back(j);
			g[j].push_back(i);
		}
	}

	vl z((1LL<<min(20LL,m)),0);
	if(m>20){
		rep(i,(1LL<<(m-20))){
			bool f=true;
			ll tmp=(1LL<<20)-1;
			//矛盾がないか調べる
			rep(j,m-20){
				if((1LL<<j)&i){
					rep(k,g[j+20].size()){
						if(g[j+20][k]<20){
							tmp&=(1LL<<20)-1-(1LL<<g[j+20][k]);
						}else{
							if((1LL<<(g[j+20][k]-20))&i)f=false;
						}
					}
				}
			}
			if(f){
				z[tmp]=__popcount(i);
			}
		}
		rrep(i,(1LL<<20)){
			rep(j,20){
				z[i&((1LL<<20)-1-(1LL<<j))]=max(z[i&((1LL<<20)-1-(1LL<<j))],z[i]);
			}
		}
	}
	ll ans=1;
	rep(i,(1LL<<min(20LL,m))){
		bool f=true;
		//矛盾がないか調べる
		rep(j,min(20LL,m)){
			if((1LL<<j)&i){
				rep(k,g[j].size()){
					if(g[j][k]>=20)continue;
					if((1LL<<g[j][k])&i)f=false;
				}
			}
		}
		if(f)ans=max(ans,z[i]+__popcount(i));
	}
	cout<<ans<<endl;
	return 0;
}

//メイン
int main(){
	while(solve()==0);
	return 0;
}
accuracy: 1
time_ms: 3610
memory_kb: 12248
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define all(a) (a).begin(), (a).end()
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define rrep(i, n) for (int i = (int)(n); i >= 0; i--)
#define range(i, l, r) for (int i = (int)(l); i < (int)(r); i++)
using ll = long long;

template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    os << "[";
    for (int i = 0; i < v.size(); i++) {
        os << v[i] << (i == (v.size() - 1) ? "" : ", ");
    }
    os << "]";
    return os;
}

template <typename T1, typename T2>
ostream& operator<<(ostream& os, const pair<T1, T2> p) {
    os << "{" << p.first << ", " << p.second << "}";
    return os;
}

bool solve() {
    int n, m;
    cin >> n >> m;
    if (n == 0) return false;

    int a[n][m];
    rep(i, n) rep(j, m) cin >> a[i][j];

    if (m == 1) {
        cout << 1 << endl;
        return true;
    }

    bitset<1000000> lq[m];
    bitset<1000000> gq[m];
    rep(i, m) {
        lq[i].reset();
        gq[i].reset();
    }

    rep(t, m) rep(i, n) range(j, i + 1, n) {
        if (a[i][t] > a[j][t]) lq[t][i * n + j] = 1;
        if (a[i][t] < a[j][t]) gq[t][i * n + j] = 1;
    }

    vector<ll> ok(m, 0);
    rep(i, m) range(j, i + 1, m) {
        if (!(lq[i] & gq[j]).any() && !(lq[j] & gq[i]).any()) {
            ok[i] |= (1LL << j);
            ok[j] |= (1LL << i);
        }
    }

    int pre = m / 2;
    int suf = m - pre;

    vector<int> ok1(1 << pre, -1);
    ok1[0] = 0;
    rep(i, 1 << pre) if (i > 0) {
        int k = -1;
        bool f = true;
        rep(j, pre) if ((i & (1 << j)) != 0) {
            if (k == -1) {
                k = j;
                f &= ok1[i ^ (1 << j)] >= 0;
            } else {
                f &= ((ok[j] >> k) & 1) > 0;
            }
        }
        if (f) ok1[i] = __popcount(i);
    }

    vector<int> ok2(1 << suf, -1);
    ok2[0] = 0;
    rep(i, 1 << suf) if (i > 0) {
        int k = -1;
        bool f = true;
        rep(j, suf) if ((i & (1 << j)) != 0) {
            if (k == -1) {
                k = j;
                f &= ok2[i ^ (1 << j)] >= 0;
            } else {
                f &= ((ok[j + pre] >> (k + pre)) & 1) > 0;
            }
        }
        if (f) ok2[i] = __popcount(i);
    }

    rep(k, suf) rep(i, 1 << suf) {
        if ((i & (1 << k)) > 0) {
            ok2[i] = max(ok2[i], ok2[i ^ (1 << k)]);
        }
    }

    int ans = 0;
    rep(i, 1 << pre) if (ok1[i] >= 0) {
        ll e = (1LL << m) - 1;
        rep(j, pre) if ((i & (1 << j)) > 0) e &= ok[j];

        int g = 0;
        rep(j, suf) if ((e & (1LL << (j + pre))) > 0) g += 1 << j;
        ans = max(ans, ok1[i] + ok2[g]);
    }

    cout << ans << endl;

    return true;
}

int main() {
    while (solve()) {
    }
}
accuracy: 1
time_ms: 1450
memory_kb: 21752
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define ALL(x) x.begin(),x.end()
#define dbg(x) cerr << #x << ':' << (x) << endl;
using ll = long long;
using ld = long double;

void solve() {
    int n,m;
    cin >> n >> m;

    if (n+m == 0) exit(0);

    vector<vector<int>> a(n,vector<int>(m));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> a[i][j];
        }
    }

    // 辺を張る
    vector<vector<int>> g(m);
    for (int m1 = 0; m1 < m; m1++) {
        for (int m2 = m1+1; m2 < m; m2++) {
            vector<pair<int,int>> p(n);
            for (int i = 0; i < n; ++i) p[i] = {a[i][m1],a[i][m2]};
            sort(ALL(p));

            bool ok = true;
            for (int i = 1; i < n; ++i) {
                if (p[i-1].second > p[i].second) ok = false;
            }
            if (!ok) {
                g[m1].emplace_back(m2);
                g[m2].emplace_back(m1);
            }
        }
    }

    auto check = [&](vector<bool>& used)->bool{
        for (int i = 0; i < m; ++i) {
            if (used[i]) continue;
            for (int j : g[i]) {
                if (!used[j]) return false;
            }
        }
        return true;
    };

    auto vertex_cover = [&](auto vertex_cover, vector<bool>& used, int k)->bool{
        if (k < 0) return false;
        if (k == 0) return check(used);

        // 次数が最大の頂点を選ぶ
        int select = -1;
        int best = 0;
        int degree = 0;
        for (int i = 0; i < m; ++i) {
            if (used[i]) continue;
            int tmp = 0;
            for (int j : g[i]) {
                if (!used[j]) ++tmp;
            }
            if (best < tmp) {
                select = i;
                best = tmp;
            }
            degree += tmp;
        }

        if (best == 0) return true;

        if (best == 1) return degree/2 <= k;

        used[select] = true;
        if (vertex_cover(vertex_cover,used,k-1)) return true;
        used[select] = false;

        vector<int> tmp;
        for (int j : g[select]) {
            if (!used[j]) tmp.emplace_back(j);
        }
        for (int j : tmp) used[j] = true;
        if (vertex_cover(vertex_cover,used,k-best)) return true;
        for (int j : tmp) used[j] = false;

        return false;
    };

    for (int k = 0; k <= m; ++k) {
        vector<bool> used(m,false);
        if (vertex_cover(vertex_cover, used, k)) {
            cout << m-k << endl;
            return;
        }
    }
}

int main()
{   
    while (true) solve();
}
accuracy: 1
time_ms: 220
memory_kb: 3540
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef vector<ll> vi;
typedef vector<vi> vvi;
typedef vector<vvi> vvvi;
typedef vector<vvvi> vvvvi;
typedef vector<bool> vb;
typedef vector<vb> vvb;
typedef vector<vvb> vvvb;
typedef vector<vvvb> vvvvb;
typedef pair<ll,ll> pi;
typedef pair<ll,pi> ppi;
#define FOR(i,l,r) for(ll i=l;i<r;i++)
#define REP(i,n) FOR(i,0,n)
#define RFOR(i,l,r) for(ll i=r-1;i>=l;i--)
#define RREP(i,n) RFOR(i,0,n)
#define sz(A) (ll)(A.size())
#define ALL(A) A.begin(),A.end()
#define LB(A,x) (ll)(lower_bound(ALL(A),x)-A.begin())
#define UB(A,x) (ll)(upper_bound(ALL(A),x)-A.begin())
#define COU(A,x) (UB(A,x)-LB(A,x))
#define F first
#define S second
template<typename T>using min_priority_queue=priority_queue<T,vector<T>,greater<T>>;
template<typename T1,typename T2>ostream&operator<<(ostream&os,pair<T1,T2>&p){os<<p.F<<" "<<p.S;return os;}
template<typename T1,typename T2>istream&operator>>(istream&is,pair<T1,T2>&p){is>>p.F>>p.S;return is;}
template<typename T>ostream&operator<<(ostream&os,vector<T>&v){REP(i,sz(v))os<<v[i]<<(i+1!=sz(v)?" ":"");return os;}
template<typename T>istream&operator>>(istream&is,vector<T>&v){for(T&in:v)is>>in;return is;}
template<class T>bool chmax(T&a,T b){if(a<b){a=b;return 1;}return 0;}
template<class T>bool chmin(T&a,T b){if(b<a){a=b;return 1;}return 0;}
const ll mod=998244353;
template<const long long int mod=998244353>
struct modint{
  using mint=modint<mod>;
  long long int x;
  modint(long long int _x=0):x(_x%mod){if(x<0)x+=mod;}
  long long int val(){return x;}
  mint&operator=(const mint&a){x=a.x;return *this;}
  mint&operator+=(const mint&a){x+=a.x;if(x>=mod)x-=mod;return *this;}
  mint&operator-=(const mint&a){x-=a.x;if(x<0)x+=mod;return *this;}
  mint&operator*=(const mint&a){x*=a.x;x%=mod;return *this;}
  friend mint operator+(const mint&a,const mint&b){return mint(a)+=b;}
  friend mint operator-(const mint&a,const mint&b){return mint(a)-=b;}
  friend mint operator*(const mint&a,const mint&b){return mint(a)*=b;}
  mint operator-()const{return mint(0)-*this;}
  mint pow(long long int n){
    if(!n)return 1;
    mint a=1;
    mint _x=x;
    while(n){
      if(n&1)a*=_x;
      _x=_x*_x;n>>=1;
    }
    return a;
  }
  mint inv(){return pow(mod-2);}
  mint&operator/=(mint&a){return *this*=a.inv();}
  friend mint operator/(const mint&a,mint b){return mint(a)/=b;}
};
using mint=modint<998244353>;
int main(){
    while(1){
      ll N,M;cin>>N>>M;
      if(!N)return 0;
      vvi A(N,vi(M));cin>>A;
      vvb B(M,vb(M,1));
      REP(i,M)REP(j,i){
        vector<pi>T(N);
        REP(k,N)T[k]=pi(A[k][i],A[k][j]);
        sort(ALL(T));
        REP(k,N-1)if(T[k].S>T[k+1].S)B[i][j]=B[j][i]=0;
      }
      ll n=M/2;
      vi X(1<<n,-1),Y(1<<(M-n),-1);
      REP(i,1<<n){
        X[i]=__builtin_popcount(i);
        REP(j,n)REP(k,j)if((i>>j)%2&&(i>>k)%2&&!B[j][k])X[i]=-1;
      }
      REP(i,1<<(M-n)){
        Y[i]=__builtin_popcount(i);
        REP(j,M-n)REP(k,j)if((i>>j)%2&&(i>>k)%2&&!B[j+n][k+n])Y[i]=-1;
      }
      REP(i,1<<n){
        REP(j,n)if((i>>j)%2==0){
            chmax(X[i+(1<<j)],X[i]);
        }
      }
      ll ans=0;
      REP(i,1<<(M-n)){
        ll s=(1<<n)-1;
        REP(j,M-n)if((i>>j)%2)REP(k,n)if(!B[k][j+n])s-=s&(1<<k);
        chmax(ans,Y[i]+X[s]);
      }
      cout<<ans<<endl;
    }
    return 0;
}
accuracy: 1
time_ms: 6630
memory_kb: 19768
final_rank: 20

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

#include <unistd.h>

namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf


uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio


using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

/**
 * @brief Fast IO
 */

namespace Random {
mt19937_64 randgen(chrono::steady_clock::now().time_since_epoch().count());
using u64 = unsigned long long;
u64 get() {
    return randgen();
}
template <typename T> T get(T L) { // [0,L]

    return get() % (L + 1);
}
template <typename T> T get(T L, T R) { // [L,R]

    return get(R - L) + L;
}
double uniform() {
    return double(get(1000000000)) / 1000000000;
}
string str(int n) {
    string ret;
    rep(i, 0, n) ret += get('a', 'z');
    return ret;
}
template <typename Iter> void shuffle(Iter first, Iter last) {
    if (first == last)
        return;
    int len = 1;
    for (auto it = first + 1; it != last; it++) {
        len++;
        int j = get(0, len - 1);
        if (j != len - 1)
            iter_swap(it, first + j);
    }
}
template <typename T> vector<T> select(int n, T L, T R) { // [L,R]

    if (n * 2 >= R - L + 1) {
        vector<T> ret(R - L + 1);
        iota(ALL(ret), L);
        shuffle(ALL(ret));
        ret.resize(n);
        return ret;
    } else {
        unordered_set<T> used;
        vector<T> ret;
        while (SZ(used) < n) {
            T x = get(L, R);
            if (!used.count(x)) {
                used.insert(x);
                ret.push_back(x);
            }
        }
        return ret;
    }
}

void relabel(int n, vector<pair<int, int>> &es) {
    shuffle(ALL(es));
    vector<int> ord(n);
    iota(ALL(ord), 0);
    shuffle(ALL(ord));
    for (auto &[u, v] : es)
        u = ord[u], v = ord[v];
}
template <bool directed, bool simple> vector<pair<int, int>> genGraph(int n) {
    vector<pair<int, int>> cand, es;
    rep(u, 0, n) rep(v, 0, n) {
        if (simple and u == v)
            continue;
        if (!directed and u > v)
            continue;
        cand.push_back({u, v});
    }
    int m = get(SZ(cand));
    vector<int> ord;
    if (simple)
        ord = select(m, 0, SZ(cand) - 1);
    else {
        rep(_, 0, m) ord.push_back(get(SZ(cand) - 1));
    }
    for (auto &i : ord)
        es.push_back(cand[i]);
    relabel(n, es);
    return es;
}
vector<pair<int, int>> genTree(int n) {
    vector<pair<int, int>> es;
    rep(i, 1, n) es.push_back({get(i - 1), i});
    relabel(n, es);
    return es;
}
}; // namespace Random

/**
 * @brief Random
 */

struct MaxIndependentSet {
    const int n;
    vector<ll> es;
    MaxIndependentSet(int _n) : n(_n), es(n) {}
    void add_edge(int u, int v) {
        es[u] |= 1LL << v;
        es[v] |= 1LL << u;
    }
    pair<ll, ll> run(vector<ll> &cost, int _rot = 1e6) {
        vector<int> ord(n);
        iota(ALL(ord), 0);
        ll ret = 0;
        ll cur = 0;
        rep(_, 0, _rot) {
            Random::shuffle(ALL(ord));
            ll add = 0;
            ll used = 0;
            for (auto &v : ord)
                if (!(used & es[v])) {
                    used |= (1LL << v);
                    add += cost[v];
                }
            if (chmax(ret, add))
                cur = used;
        }
        return {ret, cur};
    }
};

/**
 * @brief Maximum Independent Set
 */

#define pii pair<int, int>
#define N 111

struct MaxClique {  // 0-base
    typedef bitset<N> Int;
    Int linkto[N], v[N];
    int n;
    void init(int _n) {
        n = _n;
        for (int i = 0; i < n; i++) {
            linkto[i].reset();
            v[i].reset();
        }
    }
    void addEdge(int a, int b) { v[a][b] = v[b][a] = 1; }
    int popcount(const Int& val) { return val.count(); }
    int lowbit(const Int& val) { return val._Find_first(); }
    int ans, stk[N];
    int id[N], di[N], deg[N];
    Int cans;
    void maxclique(int elem_num, Int candi) {
        if (elem_num > ans) {
            ans = elem_num;
            cans.reset();
            for (int i = 0; i < elem_num; i++)
                cans[id[stk[i]]] = 1;
        }
        int potential = elem_num + popcount(candi);
        if (potential <= ans)
            return;
        int pivot = lowbit(candi);
        Int smaller_candi = candi & (~linkto[pivot]);
        while (smaller_candi.count() && potential > ans) {
            int next = lowbit(smaller_candi);
            candi[next] = !candi[next];
            smaller_candi[next] = !smaller_candi[next];
            potential--;
            if (next == pivot || (smaller_candi & linkto[next]).count()) {
                stk[elem_num] = next;
                maxclique(elem_num + 1, candi & linkto[next]);
            }
        }
    }
    int solve() {
        for (int i = 0; i < n; i++) {
            id[i] = i;
            deg[i] = v[i].count();
        }
        sort(id, id + n, [&](int id1, int id2) { return deg[id1] > deg[id2]; });
        for (int i = 0; i < n; i++)
            di[id[i]] = i;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                if (v[i][j])
                    linkto[di[i]][di[j]] = 1;
        Int cand;
        cand.reset();
        for (int i = 0; i < n; i++)
            cand[i] = 1;
        ans = 1;
        cans.reset();
        cans[0] = 1;
        maxclique(0, cand);
        return ans;
    }
} solver;

int main() {
while(1) {
    int N_, M;
    cin >> N_ >> M;
    if (N_ == 0 && M == 0) return 0;
    vector A(N_,vector<int>(M));
    rep(i,0,N_) rep(j,0,M) cin >> A[i][j];
    solver.init(M);
    rep(i,0,M) {
        rep(j,i+1,M) {
            vector<pair<int,int>> X;
            rep(k,0,N_) {
                X.push_back({A[k][i],A[k][j]});
            }
            sort(X.begin(), X.end());
            bool check = true;
            rep(k,0,N_-1) {
                if (X[k].first < X[k+1].first && X[k].second > X[k+1].second) check = false;
            }
            if (check) solver.addEdge(i,j);
        }
    }
    solver.solve();
    cout << solver.ans << endl;
}
}
accuracy: 1
time_ms: 220
memory_kb: 3492
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (long long i = 0; i < (long long)(n); i++)
#define rrep(i,start,end) for (long long i = start;i >= (long long)(end);i--)
#define repn(i,end) for(long long i = 0; i <= (long long)(end); i++)
#define reps(i,start,end) for(long long i = start; i < (long long)(end); i++)
#define repsn(i,start,end) for(long long i = start; i <= (long long)(end); i++)
#define each(p,a) for(auto &p:a)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef vector<long long> vll;
typedef vector<pair<long long ,long long>> vpll;
typedef vector<vector<long long>> vvll;
typedef set<ll> sll;
typedef map<long long , long long> mpll;
typedef pair<long long ,long long> pll;
typedef tuple<long long , long long , long long> tpl3;
#define LL(...) ll __VA_ARGS__; input(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; input(__VA_ARGS__)
#define Str(...) string __VA_ARGS__; input(__VA_ARGS__)
#define Ch(...) char __VA_ARGS__; input(__VA_ARGS__)
#define all(a)  (a).begin(),(a).end()
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );
#define sz(x) (int)x.size()
// << std::fixed << std::setprecision(10)
const ll INF = 1LL << 60;
const ld EPS = 1e-9;
 
inline ll lfloor(ll x,ll m){return (x - ((x % m+ m)%m))/m;}
inline ll positive_mod(ll a,ll m){return (a % m + m)%m;}
inline ll popcnt(ull a){ return __builtin_popcountll(a);}
template<class T> bool chmin(T& a, T b){if(a > b){a = b;return true;}return false;}
template<class T> bool chmax(T& a, T b){if(a < b){a = b;return true;}return false;}
template<typename T> std::istream &operator>>(std::istream&is,std::vector<T>&v){for(T &in:v){is>>in;}return is;}
template<typename T> std::ostream &operator<<(std::ostream&os,const std::vector<T>&v){for(auto it=std::begin(v);it!=std::end(v);){os<<*it<<((++it)!=std::end(v)?" ":"");}return os;}
template<typename T1, typename T2>std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){os << "{" << p.first << "," << p.second << "}";return os;}
template<class... T>void input(T&... a){(cin >> ... >> a);}
void print(){cout << endl;}
template<class T, class... Ts>void print(const T& a, const Ts&... b){cout << a;((cout << ' ' << b), ...);cout << endl;}
template<class T> void pspace(const T& a){ cout << a << ' ';}
void perr(){cerr << endl;}
template<class T, class... Ts>void perr(const T& a, const Ts&... b){cerr << a;((cerr << ' ' << b), ...);cerr << endl;}
void yes(bool i = true){ return print(i?"yes":"no"); }
void Yes(bool i = true){ return print(i?"Yes":"No"); }
void YES(bool i = true){ return print(i?"YES":"NO"); }
template <class T> vector<T> &operator++(vector<T> &v) {for(auto &e : v) e++;return v;}
template <class T> vector<T> operator++(vector<T> &v, signed) {auto res = v;for(auto &e : v) e++;return res;}
template <class T> vector<T> &operator--(vector<T> &v) {for(auto &e : v) e--;return v;}
template <class T> vector<T> operator--(vector<T> &v, signed) {auto res = v;for(auto &e : v) e--;return res;}
//grid探索用
vector<ll> _ta = {0,0,1,-1,1,1,-1,-1};
vector<ll> _yo = {1,-1,0,0,1,-1,1,-1};
bool isin(ll now_i,ll now_j,ll h,ll w){return (0<=now_i && now_i < h && 0 <= now_j && now_j < w);}
  
ll lpow(ll x,ll n){ll ans = 1;while(n >0){if(n & 1)ans *= x;x *= x;n >>= 1;}return ans;}
ll Modlpow(ll x,ll n,ll m){ll ans = 1;ll a = x%m;while(n >0){if(n & 1){ans *= a;ans%= m;}a *= a;a %= m;n >>= 1;}return ans;} 
const ll MOD9 = 998244353LL;
const ll MOD10 = 1000000007LL;

// for AOJ or ICPC or etc..
// 全部が0だったらtrueを返す
template<class Tp> bool zero (const Tp &x) {return x == 0;}
template<class Tp, class... Args> bool zero (const Tp &x, const Args& ...args) {return zero(x) and zero(args...);}


// 変数をちゃんと全部受け取る！
void solve(ll n,ll m){
  vvll a(n,vll(m));
  rep(i,n)rep(j,m){
    cin >> a[i][j];
  };
  //ダメなヤツのグラフ作る
  vector<set<ll>> g(m);
  set<pll> se;
  rep(i,m)rep(j,i){
    auto cp = [&](vll &x, vll &y){
      if(x[i] < y[i]){
        return true;
      }else if(x[i] == y[i]){
        return x[j] < y[j];
      }else{
        return false;
      }
    };
    sort(all(a),cp);
    bool ok = true;
    rep(k,n-1){
      if(a[k][i] > a[k+1][i] or a[k][j] > a[k+1][j]){
        ok = false;
        break;
      }
    }
    if(!ok){
      se.insert({i,j});
      se.insert({j,i});
      g[i].insert(j);
      g[j].insert(i);
    }
  }
  //半分全列挙
  ll pm = m/2;
  ll qm = m - pm;
  vll dp(1 << pm,1);
  dp[0] = 0;
  rep(i,1 << pm){
    vll tmp;
    bool ok = true;
    rep(j,pm){
      if(i >> j & 1){
        each(p,tmp){
          if(g[j].count(p)){
            ok = false;
          }
        }
        tmp.push_back(j);
      }
    }
    if(ok){
      dp[i] = popcnt(i);
    }
  }
  rep(i,1 << pm){
    rep(j,pm){
      if(~i >>j & 1){
        chmax(dp[i + (1 << j)],dp[i]);
      }
    }
  }
  ll ans = 1;
  rep(i,1 << qm){
    ll to = (1 << pm) -1;
    vll tmp;
    bool ok = true;
    rep(j,qm){
      if(i >> j & 1){
        each(p,tmp){
          if(g[j + pm].count(p))ok = false;
        }
        each(p,g[j + pm]){
          if(to >> p & 1){
            to -= 1 << p;
          }
        }
        tmp.push_back(j + pm);
      }
    }
    if(ok){
      chmax(ans,dp[to] + popcnt(i));
    }

  }
  cout << ans << endl;



}
 
int main(){
  ios::sync_with_stdio(false);cin.tie(nullptr);
  while(true){
    LL(n,m);//変数数調整
    if(zero(n,m))break;
    solve(n,m);
  }
}
accuracy: 1
time_ms: 6710
memory_kb: 13528
final_rank: 19

code_snippet: #if 1
// clang-format off
#include <bits/stdc++.h>

using namespace std;
using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;
using lf = long double;
using pll = pair<ll, ll>;
#define vec vector
template <class T> using v = vector<T>;
template <class T> using vv = v<v<T>>;
template <class T> using vvv = v<vv<T>>;
using vl = v<ll>;
using vvl = vv<ll>;
using vvvl = vvv<ll>;
using vpl = v<pll>;
using vs = v<string>;
using vb = v<bool>;
using vvb = v<vb>;
using vvvb = v<vvb>;
template<class T> using PQ = priority_queue<T, v<T>, greater<T>>;
constexpr ll TEN(int n) { return (n == 0) ? 1 : 10 * TEN(n - 1); }

#define FOR(i, a, b) for (ll i = (ll)(a); i < (ll)(b); i++)
#define rep(i, N) for (ll i = 0; i < (ll)(N); i++)
#define rep1(i, N) for (ll i = 1; i <= (ll)(N); i++)
#define rrep(i, N) for (ll i = N - 1; i >= 0; i--)
#define rrep1(i, N) for (ll i = N; i > 0; i--)
#define fore(i, a) for (auto &i : a)
#define fs first
#define sc second
#define eb emplace_back
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define UNIQUE(x) (x).erase(unique((x).begin(), (x).end()), (x).end());
#define YES(x) cout << ((x) ? "YES\n" : "NO\n");
#define Yes(x) cout << ((x) ? "Yes\n" : "No\n");
#define yes(x) cout << ((x) ? "yes\n" : "no\n");
template <class T, class U> void chmin(T &t, const U &u) { if (t > u) t = u; }
template <class T, class U> void chmax(T &t, const U &u) { if (t < u) t = u; }
template <class T> T min(const v<T> &lis) { return *min_element(all(lis)); }
template <class T> T max(v<T> &lis) { return *max_element(all(lis)); }
const int inf = (1 << 30);
const ll infl = (1LL << 60);
const ll mod93 = 998244353;
const ll mod17 = 1000000007;
int popcnt(uint x) { return __builtin_popcount(x); }
int popcnt(ull x) { return __builtin_popcountll(x); }
// 桁数
int bsr(uint x) { return 31 - __builtin_clz(x); }
int bsr(ull x) { return 63 - __builtin_clzll(x); }
// 2で割れる回数
int bsf(uint x) { return __builtin_ctz(x); }
int bsf(ull x) { return __builtin_ctzll(x); }

template <class T, class S> istream &operator>>(istream &is, pair<T, S> &x) { return is >> x.first >> x.second; }
template <class T, class S> ostream &operator<<(ostream &os, const pair<T, S> &x) { return os << x.first << " " << x.second; }
template <class T> istream &operator>>(istream &is, vector<T> &x) { for (auto &y : x) is >> y; return is; }
template <class T> ostream &operator<<(ostream &os, const vector<T> &x) {
  for (size_t i = 0, size = x.size(); i < size; i++)
    os << x[i] << (i == size - 1 ? "" : " ");
  return os;
}

ll rand_int(ll l, ll r) {  // [l, r]
  static random_device rd;
  static mt19937 gen(rd());
  return uniform_int_distribution<ll>(l, r)(gen);
}

// #include <boost/multiprecision/cpp_int.hpp>
// using cpp_int = boost::multiprecision::cpp_int;

// clang-format on
#endif

// #define _GLIBCXX_DEBUG

struct Solver {
  void solve(ll n, ll m) {
    vvl a(n, vl(m));
    cin >> a;
    if (m == 1) {
      cout << 1 << "\n";
      return;
    }

    vvb edge(m, vb(m));
    rep(i, m) {
      FOR(j, i + 1, m) {
        vpl b(n);
        rep(k, n) { b[k] = {a[k][i], a[k][j]}; }
        sort(all(b));
        bool ok = true;
        rep(k, n - 1) { ok &= b[k].sc <= b[k + 1].sc; }
        edge[i][j] = edge[j][i] = ok;
      }
    }

    ll m1 = m / 2;
    vl dp((1 << m1));
    rep(i, (1 << m1)) {
      bool ok = true;
      rep(j, m1) {
        FOR(k, j + 1, m1) {
          if ((i >> j) & (i >> k) & 1) {
            ok &= edge[j][k];
          }
        }
      }
      if (ok) dp[i] = popcnt(uint(i));
      rep(j, m1) { chmax(dp[i | (1 << j)], dp[i]); }
    }
    // cout << dp << "\n";
    ll m2 = (m + 1) / 2;
    ll ans = 0;
    rep(i, (1 << m2)) {
      bool ok = true;
      rep(j, m2) {
        FOR(k, j + 1, m2) {
          if ((i >> j) & (i >> k) & 1) {
            ok &= edge[m1 + j][m1 + k];
          }
        }
      }
      if (!ok) continue;
      ll idx = (1 << m1) - 1;
      rep(j, m2) {
        rep(k, m1) {
          if (((i >> j) & 1) && !edge[k][m1 + j]) {
            idx &= ~(1 << k);
          }
        }
      }
      chmax(ans, popcnt(uint(i)) + dp[idx]);
    }
    cout << ans << endl;
  }
};

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(20);

  ll t = 1;
  // cin >> t;
  while (t) {
    ll n, m;
    cin >> n >> m;
    if (n == 0 && m == 0) break;
    Solver solver;
    solver.solve(n, m);
  }
}
accuracy: 1
time_ms: 3920
memory_kb: 13736
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, n) for (int i = 0; i < n; i++)
#define all(v) v.begin(), v.end()
template <class T, class U>
inline bool chmax(T &a, U b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T, class U>
inline bool chmin(T &a, U b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
constexpr int INF = 1000000000;
constexpr int64_t llINF = 3000000000000000000;
constexpr double eps = 1e-10;
const double pi = acos(-1);
struct linear_sieve {
    vector<int> least_factor, prime_list;
    linear_sieve(int n) : least_factor(n + 1, 0) {
        for (int i = 2; i <= n; i++) {
            if (least_factor[i] == 0) {
                least_factor[i] = i;
                prime_list.push_back(i);
            }
            for (int p : prime_list) {
                if (ll(i) * p > n || p > least_factor[i]) break;
                least_factor[i * p] = p;
            }
        }
    }
};
ll extgcd(ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
ll modpow(ll a, ll b, ll m) {
    ll res = 1;
    while (b) {
        if (b & 1) {
            res *= a;
            res %= m;
        }
        a *= a;
        a %= m;
        b >>= 1;
    }
    return res;
}
template <int modulo>
struct modint {
    int x;
    modint() : x(0) {}
    modint(int64_t y) : x(y >= 0 ? y % modulo : (modulo - (-y) % modulo) % modulo) {}
    modint &operator+=(const modint &p) {
        if ((x += p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator-=(const modint &p) {
        if ((x += modulo - p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator*=(const modint &p) {
        x = (int)(1LL * x * p.x % modulo);
        return *this;
    }
    modint &operator/=(const modint &p) {
        *this *= p.inv();
        return *this;
    }
    modint operator-() const { return modint(-x); }
    modint operator+(const modint &p) const { return modint(*this) += p; }
    modint operator-(const modint &p) const { return modint(*this) -= p; }
    modint operator*(const modint &p) const { return modint(*this) *= p; }
    modint operator/(const modint &p) const { return modint(*this) /= p; }
    bool operator==(const modint &p) const { return x == p.x; }
    bool operator!=(const modint &p) const { return x != p.x; }
    modint inv() const {
        int a = x, b = modulo, u = 1, v = 0, t;
        while (b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return modint(u);
    }
    modint pow(int64_t n) const {
        modint ret(1), mul(x);
        while (n > 0) {
            if (n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }
    friend ostream &operator<<(ostream &os, const modint &p) { return os << p.x; }
    friend istream &operator>>(istream &is, modint &a) {
        int64_t t;
        is >> t;
        a = modint<modulo>(t);
        return (is);
    }
    int val() const { return x; }
    static constexpr int mod() { return modulo; }
    static constexpr int half() { return (modulo + 1) >> 1; }
};
template <typename T>
struct Binomial {
    vector<T> inv, fact, factinv;
    Binomial(int n) {
        inv.resize(n + 1);
        fact.resize(n + 1);
        factinv.resize(n + 1);
        inv[0] = fact[0] = factinv[0] = 1;
        for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i;
        factinv[n] = fact[n].inv();
        inv[n] = fact[n - 1] * factinv[n];
        for (int i = n - 1; i >= 1; i--) {
            factinv[i] = factinv[i + 1] * (i + 1);
            inv[i] = fact[i - 1] * factinv[i];
        }
    }
    T C(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r] * factinv[r];
    }
    T P(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r];
    }
    T H(int n, int r) {
        if (n == 0 && r == 0) return 1;
        if (n < 0 || r < 0) return 0;
        return r == 0 ? 1 : C(n + r - 1, r);
    }
};
template <class T>
struct Matrix {
    int n;
    vector<vector<T>> m;
    Matrix() : Matrix(0) {}
    Matrix(int x) : Matrix(vector<vector<T>>(x, vector<T>(x, 0))) {}
    Matrix(const vector<vector<T>> &a) {
        n = a.size();
        m = a;
    }
    vector<T> &operator[](int i) { return m[i]; }
    const vector<T> &operator[](int i) const { return m[i]; }
    static Matrix identity(int x) {
        Matrix res(x);
        for (int i = 0; i < x; i++) res[i][i] = 1;
        return res;
    }
    Matrix operator+(const Matrix &a) const {
        Matrix x = (*this);
        return x += a;
    }
    Matrix operator*(const Matrix &a) const {
        Matrix x = (*this);
        return x *= a;
    }
    Matrix &operator+=(const Matrix &a) {
        Matrix res(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                res[i][j] = m[i][j] + a[i][j];
            }
        }
        m = res.m;
        return *this;
    }
    Matrix &operator*=(const Matrix &a) {
        Matrix res(n);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) {
                    res[i][j] += m[i][k] * a[k][j];
                }
            }
        }
        m = res.m;
        return *this;
    }
    Matrix pow(ll b) const {
        Matrix x = *this, res = identity(n);
        while (b) {
            if (b & 1) {
                res *= x;
            }
            x *= x;
            b >>= 1;
        }
        return res;
    }
};
template <class S, S (*op)(S, S), S (*e)()>
struct segtree {
    int siz = 1;
    vector<S> dat;
    segtree(int n) : segtree(vector<S>(n, e())) {}
    segtree(const vector<S> &a) {
        while (siz < a.size()) siz <<= 1;
        dat = vector<S>(siz << 1, e());
        for (int i = 0; i < a.size(); i++) dat[siz + i] = a[i];
        for (int i = siz - 1; i >= 1; i--) dat[i] = op(dat[2 * i], dat[2 * i + 1]);
    }
    void set(int p, S x) {
        p += siz;
        dat[p] = x;
        while (p > 0) {
            p >>= 1;
            dat[p] = op(dat[2 * p], dat[2 * p + 1]);
        }
    }
    void add(int p, S x) { set(p, get(p) + x); }
    S get(int p) { return dat[p + siz]; }
    S prod(int l, int r) {
        S vl = e(), vr = e();
        l += siz, r += siz;
        while (l < r) {
            if (l & 1) vl = op(vl, dat[l++]);
            if (r & 1) vr = op(dat[--r], vr);
            l >>= 1, r >>= 1;
        }
        return op(vl, vr);
    }
    S all_prod() { return dat[1]; }
};

template <class T>
struct BIT {
    // 1-indexed
    int n, beki = 1;
    vector<T> bit;
    BIT(int x) {
        bit.resize(x + 1, 0);
        n = x;
        while (beki * 2 <= n) beki *= 2;
    }
    T sum(int i) {
        T res = 0;
        while (i > 0) {
            res += bit[i];
            i -= i & -i;
        }
        return res;
    }
    T sum(int l, int r) {
        //[l,r]
        return sum(r) - (l == 0 ? 0 : sum(l - 1));
    }
    void add(int i, T x) {
        while (i <= n) {
            bit[i] += x;
            i += i & -i;
        }
    }
    int lowerbound(T w) {
        if (w <= 0) return 0;
        int x = 0;
        for (int k = beki; k > 0; k >>= 1) {
            if (x + k <= n && bit[x + k] < w) {
                w -= bit[x + k];
                x += k;
            }
        }
        return x + 1;
    }
};
template <class T, T (*op)(T, T), T (*e)()>
struct sparsetable {
    vector<vector<T>> table;
    vector<int> logtable;
    sparsetable(vector<T> v) {
        int len = 0;
        while ((1 << len) <= v.size()) len++;
        table.assign(len, vector<T>(1 << len));
        for (int i = 0; i < (int)v.size(); i++) table[0][i] = v[i];
        for (int i = 1; i < len; i++) {
            for (int j = 0; j + (1 << i) <= (1 << len); j++) {
                table[i][j] = op(table[i - 1][j], table[i - 1][j + (1 << (i - 1))]);
            }
        }
        logtable.resize(v.size() + 1);
        for (int i = 2; i < logtable.size(); i++) {
            logtable[i] = logtable[(i >> 1)] + 1;
        }
    }
    T query(int l, int r) {
        assert(l <= r);
        if (l == r) return e();
        int len = logtable[r - l];
        return op(table[len][l], table[len][r - (1 << len)]);
    }
};
template <class T, T (*op)(T, T), T (*e)()>
struct disjointsparsetable {
    vector<vector<T>> table;
    vector<int> logtable;
    disjointsparsetable(vector<T> v) {
        int len = 0;
        while ((1 << len) <= v.size()) len++;
        table.assign(len, vector<T>(1 << len, e()));
        for (int i = 0; i < (int)v.size(); i++) table[0][i] = v[i];
        for (int i = 1; i < len; i++) {
            int shift = 1 << i;
            for (int j = 0; j < (int)v.size(); j += shift << 1) {
                int t = min(j + shift, (int)v.size());
                table[i][t - 1] = v[t - 1];
                for (int k = t - 2; k >= j; k--) table[i][k] = op(v[k], table[i][k + 1]);
                if (v.size() <= t) break;
                table[i][t] = v[t];
                int r = min(t + shift, (int)v.size());
                for (int k = t + 1; k < r; k++) table[i][k] = op(table[i][k - 1], v[k]);
            }
        }
        logtable.resize(1 << len);
        for (int i = 2; i < logtable.size(); i++) {
            logtable[i] = logtable[(i >> 1)] + 1;
        }
    }
    T query(int l, int r) {
        if (l == r) return e();
        if (l >= --r) return table[0][l];
        int len = logtable[l ^ r];
        return op(table[len][l], table[len][r]);
    };
};
struct lca_tree {
    int n, size;
    vector<vector<int>> par;
    vector<int> depth;
    lca_tree(vector<vector<int>> g, int root = 0) : n((int)g.size()), size(log2(n) + 2), par(size, vector<int>(n, -1)), depth(vector<int>(n, n)) {
        queue<int> que;
        depth[root] = 0;
        que.push(root);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            for (int i : g[p]) {
                if (depth[i] > depth[p] + 1) {
                    depth[i] = depth[p] + 1;
                    par[0][i] = p;
                    que.push(i);
                }
            }
        }
        for (int k = 0; k < size - 1; k++) {
            for (int i = 0; i < n; i++) {
                if (par[k][i] == -1)
                    par[k + 1][i] = -1;
                else
                    par[k + 1][i] = par[k][par[k][i]];
            }
        }
    }
    int query(int u, int v) {
        if (depth[u] > depth[v]) swap(u, v);
        for (int k = size - 1; k >= 0; k--) {
            if (((depth[v] - depth[u]) >> k) & 1) v = par[k][v];
            if (u == v) return u;
        }
        for (int k = size - 1; k >= 0; k--) {
            if (par[k][u] != par[k][v]) {
                u = par[k][u];
                v = par[k][v];
            }
        }
        return par[0][u];
    }
    int dist(int u, int v) {
        int l = query(u, v);
        return depth[u] + depth[v] - 2 * depth[l];
    }
};
struct UnionFind {
    vector<int> par, siz, es;
    UnionFind(int x) {
        par.resize(x);
        siz.resize(x);
        es.resize(x);
        for (int i = 0; i < x; i++) {
            par[i] = i;
            siz[i] = 1;
            es[i] = 0;
        }
    }
    int find(int x) {
        if (par[x] == x) return x;
        return par[x] = find(par[x]);
    }
    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) {
            es[x]++;
            return false;
        }
        if (siz[x] < siz[y]) swap(x, y);
        par[y] = x;
        siz[x] += siz[y];
        es[x] += es[y] + 1;
        return true;
    }
    bool same(int x, int y) { return find(x) == find(y); }
    int size(int x) { return siz[find(x)]; }
    int edges(int x) { return es[find(x)]; }
};
struct Mo {
    int n;
    vector<pair<int, int>> lr;

    explicit Mo(int n) : n(n) {}

    void add(int l, int r) { /* [l, r) */ lr.emplace_back(l, r); }

    template <typename AL, typename AR, typename EL, typename ER, typename O>
    void build(const AL &add_left, const AR &add_right, const EL &erase_left, const ER &erase_right, const O &out) {
        int q = (int)lr.size();
        int bs = n / min<int>(n, sqrt(q));
        vector<int> ord(q);
        iota(begin(ord), end(ord), 0);
        sort(begin(ord), end(ord), [&](int a, int b) {
            int ablock = lr[a].first / bs, bblock = lr[b].first / bs;
            if (ablock != bblock) return ablock < bblock;
            return (ablock & 1) ? lr[a].second > lr[b].second : lr[a].second < lr[b].second;
        });
        int l = 0, r = 0;
        for (auto idx : ord) {
            while (l > lr[idx].first) add_left(--l);
            while (r < lr[idx].second) add_right(r++);
            while (l < lr[idx].first) erase_left(l++);
            while (r > lr[idx].second) erase_right(--r);
            out(idx);
        }
    }

    template <typename A, typename E, typename O>
    void build(const A &add, const E &erase, const O &out) {
        build(add, add, erase, erase, out);
    }
};
template <class S, S (*op)(S, S), S (*e)(), class F, S (*mapping)(F, S), F (*composition)(F, F), F (*id)()>
struct lazy_segtree {
    int _n, sz = 1;
    vector<S> dat;
    vector<F> lazy;
    lazy_segtree(vector<S> a) : _n(int(a.size())) {
        while (sz < _n) sz <<= 1;
        dat.resize(sz * 2, e());
        lazy.resize(sz * 2, id());
        rep(i, _n) dat[sz + i] = a[i];
        for (int i = sz - 1; i >= 1; i--) dat[i] = op(dat[2 * i], dat[2 * i + 1]);
    }
    void eval(int k) {
        dat[k] = mapping(lazy[k], dat[k]);
        if (k < sz) {
            lazy[k * 2] = composition(lazy[k], lazy[k * 2]);
            lazy[k * 2 + 1] = composition(lazy[k], lazy[k * 2 + 1]);
        }
        lazy[k] = id();
    }
    void apply(int a, int b, F f, int k = 1, int l = 0, int r = -1) {
        eval(k);
        if (r == -1) r = sz;
        if (r <= a || b <= l) return;
        if (a <= l && r <= b) {
            lazy[k] = composition(f, lazy[k]);
            eval(k);
            return;
        }
        int m = (l + r) >> 1;
        apply(a, b, f, 2 * k, l, m);
        apply(a, b, f, 2 * k + 1, m, r);
        dat[k] = op(dat[2 * k], dat[2 * k + 1]);
    }
    S prod(int a, int b, int k = 1, int l = 0, int r = -1) {
        eval(k);
        if (r == -1) r = sz;
        if (r <= a || b <= l) return e();
        if (a <= l && r <= b) return dat[k];
        int m = (l + r) >> 1;
        S vl = prod(a, b, 2 * k, l, m);
        S vr = prod(a, b, 2 * k + 1, m, r);
        return op(vl, vr);
    }
};

template <class S, S (*op)(S, S), S (*e)()>
struct dual_segtree {
    int sz = 1, log = 0;
    vector<S> lz;
    dual_segtree(vector<S> a) {
        int n = a.size();
        while (sz < n) {
            sz <<= 1;
            log++;
        }
        lz.assign(sz << 1, e());
        for (int i = 0; i < n; i++) lz[i + sz] = a[i];
    }
    void push(int k) {
        int b = __builtin_ctz(k);
        for (int d = log; d > b; d--) {
            lz[k >> d << 1] = op(lz[k >> d << 1], lz[k >> d]);
            lz[k >> d << 1 | 1] = op(lz[k >> d << 1 | 1], lz[k >> d]);
            lz[k >> d] = e();
        }
    }
    void apply(int l, int r, S x) {
        l += sz, r += sz;
        push(l);
        push(r);
        while (l < r) {
            if (l & 1) {
                lz[l] = op(lz[l], x);
                l++;
            }
            if (r & 1) {
                r--;
                lz[r] = op(lz[r], x);
            }
            l >>= 1, r >>= 1;
        }
    }
    S get(int k) {
        k += sz;
        S res = e();
        while (k) {
            res = op(res, lz[k]);
            k >>= 1;
        }
        return res;
    }
};
ll modinv(int x, int modulo) {
    int a = x, b = modulo, u = 1, v = 0, t;
    while (b > 0) {
        t = a / b;
        swap(a -= t * b, b);
        swap(u -= t * v, v);
    }
    return (u >= 0 ? u % modulo : (modulo - (-u) % modulo) % modulo);
}
struct auxiliary_tree : lca_tree {
    vector<int> in;
    vector<vector<int>> G;
    auxiliary_tree(vector<vector<int>> &g) : lca_tree(g), in((int)g.size()), G((int)g.size()) {
        int t = 0;
        dfs(0, -1, t, g);
    }
    void dfs(int v, int p, int &t, vector<vector<int>> &g) {
        in[v] = t++;
        for (auto u : g[v]) {
            if (u != p) dfs(u, v, t, g);
        }
    }
    using lca_tree::depth;
    pair<int, vector<int>> query(vector<int> vs, bool decending = false) {
        // decending: only parent to child
        assert(!vs.empty());
        sort(vs.begin(), vs.end(), [&](int a, int b) { return in[a] < in[b]; });
        int m = vs.size();
        stack<int> st;
        st.push(vs[0]);
        for (int i = 0; i < m - 1; i++) {
            int w = lca_tree::query(vs[i], vs[i + 1]);
            if (w != vs[i]) {
                int l = st.top();
                st.pop();
                while (!st.empty() && depth[w] < depth[st.top()]) {
                    if (!decending) G[l].push_back(st.top());
                    G[st.top()].push_back(l);
                    l = st.top();
                    st.pop();
                }
                if (st.empty() || st.top() != w) {
                    st.push(w);
                    vs.push_back(w);
                }
                if (!decending) G[l].push_back(w);
                G[w].push_back(l);
            }
            st.push(vs[i + 1]);
        }
        while (st.size() > 1) {
            int x = st.top();
            st.pop();
            if (!decending) G[x].push_back(st.top());
            G[st.top()].push_back(x);
        }
        // {root,vertex_list}
        return make_pair(st.top(), vs);
    }
    void clear(vector<int> vs) {
        for (int v : vs) G[v].clear();
    }
};
/*
#include <atcoder/convolution>
template <int T>
inline std::ostream &operator<<(std::ostream &os, const atcoder::static_modint<T> &p) {
    return os << p.val();
}
template <int T>
inline std::istream &operator>>(std::istream &is, atcoder::static_modint<T> &a) {
    int64_t t;
    is >> t;
    a = t;
    return is;
}

template <typename mint>
struct FormalPowerSeries : vector<mint> {
    using vector<mint>::vector;
    using FPS = FormalPowerSeries;
    FPS &operator+=(const FPS &r) {
        if (r.size() > this->size()) this->resize(r.size());
        for (int i = 0; i < (int)r.size(); i++) (*this)[i] += r[i];
        return *this;
    }
    FPS &operator+=(const mint &r) {
        if (this->empty()) this->resize(1);
        (*this)[0] += r;
        return *this;
    }

    FPS &operator-=(const FPS &r) {
        if (r.size() > this->size()) this->resize(r.size());
        for (int i = 0; i < (int)r.size(); i++) (*this)[i] -= r[i];
        return *this;
    }

    FPS &operator-=(const mint &r) {
        if (this->empty()) this->resize(1);
        (*this)[0] -= r;
        return *this;
    }
    FPS &operator*=(const FPS &r) {
        if (this->empty() || r.empty()) {
            this->clear();
            return *this;
        }
        assert(mint::mod() == 998244353);
        vector<mint> prod = atcoder::convolution(*this, r);
        this->resize((int)prod.size());
        for (int i = 0; i < (int)this->size(); i++) (*this)[i] = prod[i];
        return *this;
    }
    FPS &operator*=(const mint &v) {
        for (int i = 0; i < (int)this->size(); i++) (*this)[i] *= v;
        return *this;
    }
    FPS &operator/=(const FPS &r) {
        if (this->size() < r.size()) {
            this->clear();
            return *this;
        }
        int n = this->size() - r.size() + 1;
        return *this = (rev().pre(n) * r.rev().inv(n)).pre(n).rev();
    }
    FPS &operator%=(const FPS &r) {
        *this -= *this / r * r;
        shrink();
        return *this;
    }
    FPS operator+(const FPS &r) const { return FPS(*this) += r; }
    FPS operator+(const mint &v) const { return FPS(*this) += v; }
    FPS operator-(const FPS &r) const { return FPS(*this) -= r; }
    FPS operator-(const mint &v) const { return FPS(*this) -= v; }
    FPS operator*(const FPS &r) const { return FPS(*this) *= r; }
    FPS operator*(const mint &v) const { return FPS(*this) *= v; }
    FPS operator/(const FPS &r) const { return FPS(*this) /= r; }
    FPS operator%(const FPS &r) const { return FPS(*this) %= r; }
    FPS operator-() const {
        FPS ret(this->size());
        for (int i = 0; i < (int)this->size(); i++) ret[i] = -(*this)[i];
        return ret;
    }
    void shrink() {
        while (this->size() && this->back() == mint(0)) this->pop_back();
    }
    FPS operator>>(int sz) const {
        if ((int)this->size() <= sz) return {};
        FPS ret(*this);
        ret.erase(ret.begin(), ret.begin() + sz);
        return ret;
    }
    FPS operator<<(int sz) const {
        FPS ret(*this);
        ret.insert(ret.begin(), sz, mint(0));
        return ret;
    }
    FPS pre(int sz) const { return FPS(begin(*this), begin(*this) + min((int)this->size(), sz)); }
    FPS rev() const {
        FPS ret(*this);
        reverse(begin(ret), end(ret));
        return ret;
    }
    FPS diff() const {
        const int n = this->size();
        FPS ret(max(0, n - 1));
        for (int i = 1; i < n; i++) ret[i - 1] = (*this)[i] * mint(i);
        return ret;
    }
    FPS integral() const {
        const int n = this->size();
        FPS ret(n + 1);
        ret[0] = mint(0);
        if (n > 0) ret[1] = mint(1);
        auto mod = mint::mod();
        for (int i = 2; i <= n; i++) ret[i] = (-ret[mod % i] * (mod / i));
        for (int i = 0; i < n; i++) ret[i + 1] *= (*this)[i];
        return ret;
    }
    FPS inv(int deg = -1) const {
        assert(((*this)[0]) != mint(0));
        const int n = this->size();
        if (deg == -1) deg = n;
        FPS ret({mint(1) / (*this)[0]});
        for (int i = 1; i < deg; i <<= 1) {
            ret = (ret + ret - ret * ret * pre(i << 1)).pre(i << 1);
        }
        return ret.pre(deg);
    }
    FPS log(int deg = -1) {
        assert((*this)[0] == mint(1));
        if (deg == -1) deg = this->size();
        return (this->diff() * this->inv(deg)).pre(deg - 1).integral();
    }
    FPS exp(int deg = -1) const {
        assert((*this)[0] == mint(0));
        const int n = this->size();
        if (deg == -1) deg = n;
        FPS ret({mint(1)});
        for (int i = 1; i < deg; i <<= 1) {
            ret = (ret * (pre(i << 1) + mint(1) - ret.log(i << 1))).pre(i << 1);
        }
        return ret.pre(deg);
    }
    FPS pow(int64_t k, int deg = -1) const {
        const int n = this->size();
        if (deg == -1) deg = n;
        if (k == 0) {
            FPS ret(deg);
            if (deg) ret[0] = 1;
            return ret;
        }
        for (int i = 0; i < n; i++) {
            if ((*this)[i] != mint(0)) {
                mint rev = mint(1) / (*this)[i];
                FPS ret = (((*this * rev) >> i).log(deg) * k).exp(deg);
                ret *= (*this)[i].pow(k);
                ret = (ret << (i * k)).pre(deg);
                if ((int)ret.size() < deg) ret.resize(deg, mint(0));
                return ret;
            }
            if (__int128_t(i + 1) * k >= deg) return FPS(deg, mint(0));
        }
        return FPS(deg, mint(0));
    }
    FPS sqrt(int deg = -1) const {
        const int n = this->size();
        if (deg == -1) deg = n;
        if (n == 0) return FPS(deg, 0);
        if ((*this)[0] == mint(0)) {
            for (int i = 1; i < n; i++) {
                if ((*this)[i] != mint(0)) {
                    if (i & 1) return {};
                    if (deg - i / 2 <= 0) break;
                    auto ret = (*this >> i).sqrt(deg - i / 2);
                    if (ret.empty()) return {};
                    ret = ret << (i / 2);
                    if ((int)ret.size() < deg) ret.resize(deg, mint(0));
                    return ret;
                }
            }
            return FPS(deg, 0);
        }
        int64_t sqr = mod_sqrt((*this)[0].val(), mint::mod());
        if (sqr == -1) return {};
        assert(sqr * sqr % mint::mod() == (*this)[0].val());
        FPS ret({mint(sqr)});
        mint inv2 = mint(2).inv();
        for (int i = 1; i < deg; i <<= 1) {
            ret = (ret + pre(i << 1) * ret.inv(i << 1)) * inv2;
        }
        return ret.pre(deg);
    }
    mint eval(mint x) const {
        mint r = 0, w = 1;
        for (auto &v : *this) r += w * v, w *= x;
        return r;
    }
};
// calculate f(x + a)
template <typename mint>
FormalPowerSeries<mint> TaylorShift(FormalPowerSeries<mint> f, mint a, Binomial<mint> &bin) {
    int n = f.size();
    for (int i = 0; i < n; i++) f[i] *= bin.fact[i];
    f = f.rev();
    FormalPowerSeries<mint> g(n, mint(1));
    for (int i = 1; i < n; i++) g[i] = g[i - 1] * a * bin.inv[i];
    f = (f * g).pre(n);
    f = f.rev();
    for (int i = 0; i < n; i++) f[i] *= bin.factinv[i];
    return f;
}
template <typename mint>
FormalPowerSeries<mint> FPS_Product(vector<FormalPowerSeries<mint>> f) {
    int n = (int)f.size();
    if (n == 0) return {1};
    function<FormalPowerSeries<mint>(int, int)> calc = [&](int l, int r) {
        if (r - l == 1) return f[l];
        int m = (l + r) / 2;
        return calc(l, m) * calc(m, r);
    };
    return calc(0, n);
}
#include <atcoder/string>
int string_period(string s) {
    int n = s.size();
    auto z = atcoder::z_algorithm(s);
    for (int i = 1; i < n; i++) {
        if (n % i == 0 && z[i] == n - i) return i;
    }
    return n;
}
*/
struct LowLink {
    vector<vector<int>> g;
    vector<int> ord, low, out;
    vector<bool> used;
    vector<pair<int, int>> bridge;
    vector<pair<int, int>> articulation;
    int unions;
    LowLink(vector<vector<int>> g) : g(g) {
        int n = (int)g.size();
        ord.resize(n);
        low.resize(n);
        out.resize(n);
        used.resize(n);
        unions = 0;
        int t = 0;
        for (int i = 0; i < n; i++) {
            if (!used[i]) {
                dfs(i, t, -1);
                unions++;
            }
        }
    }
    void dfs(int v, int &t, int par) {
        used[v] = true;
        ord[v] = t++, low[v] = ord[v];
        int cnt = 0;
        bool par_back = false;
        for (int to : g[v]) {
            if (!used[to]) {
                dfs(to, t, v);
                low[v] = min(low[v], low[to]);
                if (ord[v] < low[to]) bridge.push_back(minmax(v, to));
                if (ord[v] <= low[to]) cnt++;
            } else if (to != par || par_back) {
                low[v] = min(low[v], ord[to]);
            } else
                par_back = true;
        }
        if (par != -1) cnt++;
        if (cnt >= 2) articulation.push_back({v, cnt});
        out[v] = t;
    }
};
void solve(int n, int m) {
    vector<vector<int>> a(n, vector<int>(m));
    rep(i, n) rep(j, m) cin >> a[i][j];
    vector<ll> g(m);
    rep(i, m) g[i] = 1LL << i;
    rep(i, m) {
        rep(j, i) {
            vector<pair<int, int>> p(n);
            rep(k, n) p[k] = {a[k][i], a[k][j]};
            sort(all(p));
            bool flag = true;
            rep(k, n - 1) {
                if (p[k].second > p[k + 1].second) flag = false;
            }
            if (flag) {
                g[i] |= 1LL << j;
                g[j] |= 1LL << i;
            }
        }
    }
    n = m / 2;
    vector<int> pc(1 << (m - n));
    rep(i, pc.size()) {
        rep(j, m - n) {
            if ((i >> j) & 1) pc[i]++;
        }
    }
    vector<int> ma(1 << n, -INF);
    rep(i, 1 << (m - n)) {
        bool flag = true;
        ll target = (1 << n) - 1;
        rep(j, m - n) {
            if ((i >> j) & 1) {
                if (((g[j + n] >> n) & i) != i) flag = false;
                target &= g[j + n];
            }
        }
        if (flag) chmax(ma[target], pc[i]);
    }
    // targetの部分集合でもいい
    for (int i = (1 << n) - 1; i >= 0; i--) {
        rep(j, n) {
            if ((i >> j) & 1) chmax(ma[i - (1 << j)], ma[i]);
        }
    }
    int ans = 0;
    rep(i, 1 << n) {
        bool flag = true;
        rep(j, n) {
            if ((i >> j) & 1) {
                if ((g[j] & i) != i) flag = false;
            }
        }
        if (flag) chmax(ans, ma[i] + pc[i]);
    }
    cout << ans << endl;
}
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n, m, k;
    string s;
    while (cin >> n >> m) {
        if (n == 0 && m == 0) break;
        solve(n, m);
    }
}
accuracy: 1
time_ms: 1260
memory_kb: 11620
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using P = pair<ll, ll>;
#define rep(i, a, b) for(ll i = a; i < b; ++i)
#define rrep(i, a, b) for(ll i = a; i >= b; --i)
constexpr ll inf = 4e18;
struct SetupIO {
    SetupIO() {
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout << fixed << setprecision(30);
    }
} setup_io;
template <typename T>
struct Edge {
    int from, to;
    T cost;
    int idx;
    Edge()
        : from(-1), to(-1), cost(-1), idx(-1) {}
    Edge(int from, int to, const T& cost = 1, int idx = -1)
        : from(from), to(to), cost(cost), idx(idx) {}
    operator int() const {
        return to;
    }
};
template <typename T>
struct Graph {
    Graph(int N)
        : n(N), es(0), g(N) {}
    int size() const {
        return n;
    }
    int edge_size() const {
        return es;
    }
    void add_edge(int from, int to, const T& cost = 1) {
        assert(0 <= from and from < n);
        assert(0 <= to and to < n);
        g[from].emplace_back(from, to, cost, es);
        g[to].emplace_back(to, from, cost, es++);
    }
    void add_directed_edge(int from, int to, const T& cost = 1) {
        assert(0 <= from and from < n);
        assert(0 <= to and to < n);
        g[from].emplace_back(from, to, cost, es++);
    }
    inline vector<Edge<T>>& operator[](const int& k) {
        assert(0 <= k and k < n);
        return g[k];
    }
    inline const vector<Edge<T>>& operator[](const int& k) const {
        assert(0 <= k and k < n);
        return g[k];
    }

   private:
    int n, es;
    vector<vector<Edge<T>>> g;
};
template <typename T>
using Edges = vector<Edge<T>>;
int main(void) {
    while(true) {
        int n, m;
        cin >> n >> m;
        if(n == 0 and m == 0) break;
        vector<vector<int>> a(n, vector<int>(m));
        rep(i, 0, n) {
            rep(j, 0, m) {
                cin >> a[i][j];
            }
        }
        Graph<int> g(m);
        rep(i, 0, m) {
            rep(j, i + 1, m) {
                vector<pair<int, int>> val(n);
                rep(k, 0, n) {
                    val[k] = {a[k][i], a[k][j]};
                }
                sort(val.begin(), val.end());
                bool flag = true;
                rep(k, 0, n - 1) {
                    if(val[k].second > val[k + 1].second) {
                        flag = false;
                    }
                }
                if(flag) {
                    g.add_edge(i, j);
                }
            }
        }
        int m1 = m / 2, m2 = m - m1;
        vector<bool> dp1(1 << m1), dp2(1 << m2);
        vector<int> dp3(1 << m1);
        dp1[0] = true;
        dp2[0] = true;
        int ans = 0;
        rep(mask, 1, 1 << m1) {
            rep(i, 0, m1) {
                if(mask & (1 << i)) {
                    bool flag = dp1[mask ^ (1 << i)];
                    int cnt = 0;
                    for(const auto& e : g[i]) {
                        if(e.to >= m1) continue;
                        if(mask & (1 << e.to)) {
                            cnt++;
                        }
                    }
                    if(cnt + 1 != __builtin_popcount(mask)) {
                        flag = false;
                    }
                    dp1[mask] = flag;
                    if(flag) {
                        dp3[mask] = max(dp3[mask], __builtin_popcount(mask));
                        ans = max(ans, __builtin_popcount(mask));
                    }
                    dp3[mask] = max(dp3[mask], dp3[mask ^ (1 << i)]);
                }
            }
        }
        rep(mask, 1, 1 << m2) {
            rep(i, 0, m2) {
                if(mask & (1 << i)) {
                    bool flag = dp2[mask ^ (1 << i)];
                    int cnt = 0;
                    for(const auto& e : g[m1 + i]) {
                        if(e.to < m1) continue;
                        if(mask & (1 << (e.to - m1))) {
                            cnt++;
                        }
                    }
                    if(cnt + 1 != __builtin_popcount(mask)) {
                        flag = false;
                    }
                    if(flag) {
                        ans = max(ans, __builtin_popcount(mask));
                    }
                    dp2[mask] = flag;
                    break;
                }
            }
        }
        vector<int> dp4(1 << m2, -1);
        dp4[0] = 0;
        rep(i, 0, m2) {
            dp4[1 << i] = 0;
            for(const auto& e : g[m1 + i]) {
                if(e.to >= m1) continue;
                dp4[1 << i] |= (1 << e.to);
            }
            ans = max(ans, 1 + dp3[dp4[1 << i]]);
        }
        rep(mask, 1, 1 << m2) {
            if(!dp2[mask] or __builtin_popcount(mask) == 1) continue;
            rep(i, 0, m2) {
                if(mask & (1 << i)) {
                    if(dp4[mask ^ (1 << i)] != -1) {
                        int flag = 0;
                        for(const auto& e : g[m1 + i]) {
                            if(e.to >= m1) continue;
                            if(dp4[mask ^ (1 << i)] & (1 << e.to)) {
                                flag |= (1 << e.to);
                            }
                        }
                        dp4[mask] = flag;
                        ans = max(ans, __builtin_popcount(mask) + dp3[flag]);
                    }
                    break;
                }
            }
        }
        cout << ans << '\n';
    }
}
accuracy: 1
time_ms: 4200
memory_kb: 12032
final_rank: 14