#include using namespace std; const int N = 1005, INF = 1e9 + 1337; const int dx[] = {-1, 0, 1, 0}, dy[] = {0, -1, 0, 1}; int n, m, maxL, a[N][N]; bool used[N][N]; int p[N][N], cl; vector < pair < int, int > > q[N * N]; inline bool check(int x, int y){ return 1 <= x && x <= n && 1 <= y && y <= m; } void dfsFind(int x, int y){ p[x][y] = cl; for(int i = 0; i < 4; i++){ int xx = x + dx[i], yy = y + dy[i]; if(check(xx, yy) && !p[xx][yy] && a[xx][yy] != -1){ dfsFind(xx, yy); } } } mt19937 rnd(time(nullptr)); long long ans = -1; vector < pair < int, int > > ans_path, cur_path; inline int LIS(vector < int > &q){ int n = (int)q.size(); vector < int > dp(n + 1, INF); dp[0] = -1; for(int i = 0; i < (int)q.size(); i++){ int x = q[i]; int j = upper_bound(dp.begin(), dp.end(), x) - dp.begin(); if(dp[j - 1] < x && x < dp[j]){ dp[j] = x; } } for(int i = n; i >= 0; i--){ if(dp[i] != INF){ return i; } } } inline int LDS(vector < int > &q){ int n = (int)q.size(); vector < int > dp(n + 1, INF); dp[0] = -1; for(int i = (int)q.size() - 1; i >= 0; i--){ int x = q[i]; int j = upper_bound(dp.begin(), dp.end(), x) - dp.begin(); if(dp[j - 1] < x && x < dp[j]){ dp[j] = x; } } for(int i = n; i >= 0; i--){ if(dp[i] != INF){ return i; } } } inline long long path_value(vector < pair < int, int > > &q){ vector < int > vals; for(auto it : q){ if(a[it.first][it.second] == -1){ return -2; } vals.push_back(a[it.first][it.second]); } return 1LL * LIS(vals) * LDS(vals); } /// ch1 priority OK void dfs1(int x, int y){ if((int)cur_path.size() == maxL){ long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } return; } vector < pair < int, int > > ch1, ch2; for(int i = 0; i < 4; i++){ int xx = x + dx[i], yy = y + dy[i]; if(check(xx, yy) && p[xx][yy] == p[x][y] && !used[xx][yy]){ if(a[xx][yy] != a[x][y]){ ch1.push_back(make_pair(xx, yy)); } else{ ch2.push_back(make_pair(xx, yy)); } } } if(ch1.empty() && ch2.empty()){ long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } return; } if(ch1.empty()){ int pos = rnd() % (int)ch2.size(); int xx = ch2[pos].first, yy = ch2[pos].second; used[xx][yy] = true; cur_path.push_back(make_pair(xx, yy)); dfs1(xx, yy); cur_path.pop_back(); used[xx][yy] = false; } else{ int pos = rnd() % (int)ch1.size(); int xx = ch1[pos].first, yy = ch1[pos].second; used[xx][yy] = true; cur_path.push_back(make_pair(xx, yy)); dfs1(xx, yy); cur_path.pop_back(); used[xx][yy] = false; } } /// ch2 priority OK void dfs2(int x, int y){ if((int)cur_path.size() == maxL){ long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } return; } vector < pair < int, int > > ch1, ch2; for(int i = 0; i < 4; i++){ int xx = x + dx[i], yy = y + dy[i]; if(check(xx, yy) && p[xx][yy] == p[x][y] && !used[xx][yy]){ if(a[xx][yy] != a[x][y]){ ch1.push_back(make_pair(xx, yy)); } else{ ch2.push_back(make_pair(xx, yy)); } } } if(ch1.empty() && ch2.empty()){ long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } return; } if(ch2.empty()){ int pos = rnd() % (int)ch1.size(); int xx = ch1[pos].first, yy = ch1[pos].second; used[xx][yy] = true; cur_path.push_back(make_pair(xx, yy)); dfs2(xx, yy); cur_path.pop_back(); used[xx][yy] = false; } else{ int pos = rnd() % (int)ch2.size(); int xx = ch2[pos].first, yy = ch2[pos].second; used[xx][yy] = true; cur_path.push_back(make_pair(xx, yy)); dfs2(xx, yy); cur_path.pop_back(); used[xx][yy] = false; } } /// random 0/1 priority OK void dfs3(int x, int y){ if((int)cur_path.size() == maxL){ long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } return; } vector < pair < int, int > > ch1, ch2; for(int i = 0; i < 4; i++){ int xx = x + dx[i], yy = y + dy[i]; if(check(xx, yy) && p[xx][yy] == p[x][y] && !used[xx][yy]){ if(a[xx][yy] != a[x][y]){ ch1.push_back(make_pair(xx, yy)); } else{ ch2.push_back(make_pair(xx, yy)); } } } if(ch1.empty() && ch2.empty()){ long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } return; } if(ch2.empty()){ int pos = rnd() % (int)ch1.size(); int xx = ch1[pos].first, yy = ch1[pos].second; used[xx][yy] = true; cur_path.push_back(make_pair(xx, yy)); dfs3(xx, yy); cur_path.pop_back(); used[xx][yy] = false; } else if(ch1.empty()){ int pos = rnd() % (int)ch2.size(); int xx = ch2[pos].first, yy = ch2[pos].second; used[xx][yy] = true; cur_path.push_back(make_pair(xx, yy)); dfs3(xx, yy); cur_path.pop_back(); used[xx][yy] = false; } else if(rnd() & 1){ int pos = rnd() % (int)ch1.size(); int xx = ch1[pos].first, yy = ch1[pos].second; used[xx][yy] = true; cur_path.push_back(make_pair(xx, yy)); dfs3(xx, yy); cur_path.pop_back(); used[xx][yy] = false; } else{ int pos = rnd() % (int)ch2.size(); int xx = ch2[pos].first, yy = ch2[pos].second; used[xx][yy] = true; cur_path.push_back(make_pair(xx, yy)); dfs3(xx, yy); cur_path.pop_back(); used[xx][yy] = false; } } /// greedy OK void dfs4(int x, int y){ if((int)cur_path.size() == maxL){ long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } return; } vector < pair < int, int > > ch1, ch2; for(int i = 0; i < 4; i++){ int xx = x + dx[i], yy = y + dy[i]; if(check(xx, yy) && p[xx][yy] == p[x][y] && !used[xx][yy]){ if(a[xx][yy] != a[x][y]){ ch1.push_back(make_pair(xx, yy)); } else{ ch2.push_back(make_pair(xx, yy)); } } } if(ch1.empty() && ch2.empty()){ long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } return; } random_shuffle(ch1.begin(), ch1.end()); long long mx = -1; int xx, yy; for(auto it : ch1){ cur_path.push_back(it); long long res = path_value(cur_path); if(res > mx){ mx = res; xx = it.first; yy = it.second; } cur_path.pop_back(); } random_shuffle(ch2.begin(), ch2.end()); for(auto it : ch2){ cur_path.push_back(it); long long res = path_value(cur_path); if(res > mx){ mx = res; xx = it.first; yy = it.second; } cur_path.pop_back(); } cur_path.push_back(make_pair(xx, yy)); used[xx][yy] = true; dfs4(xx, yy); used[xx][yy] = false; cur_path.pop_back(); } /** 3 3 1 3 -1 -1 2 1 -1 1 1 4 1 5 4 3 -1 2 3 4 */ int main(){ srand(time(nullptr)); ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); freopen("path.in", "r", stdin);freopen("path.out", "w", stdout); clock_t begin_t = clock(); cin >> n >> m; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ cin >> a[i][j]; } } cin >> maxL; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(!p[i][j] && a[i][j] != -1){ cl++; dfsFind(i, j); } } } for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(a[i][j] != -1){ q[p[i][j]].push_back(make_pair(i, j)); } } } if(n == 1){ for(int i = 1; i <= m; i++){ for(int j = i; j <= min(i + maxL - 1, m); j++){ cur_path.push_back(make_pair(1, j)); } long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } cur_path.clear(); } for(int i = m; i >= 1; i--){ for(int j = i; j >= max(i - maxL + 1, 1); j--){ cur_path.push_back(make_pair(1, j)); } long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } cur_path.clear(); } } if(m == 1){ for(int i = 1; i <= n; i++){ for(int j = i; j <= min(i + maxL - 1, n); j++){ cur_path.push_back(make_pair(j, 1)); } long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } cur_path.clear(); } for(int i = n; i >= 1; i--){ for(int j = i; j >= max(i - maxL + 1, 1); j--){ cur_path.push_back(make_pair(j, 1)); } long long res = path_value(cur_path); if(res > ans){ ans = res; ans_path = cur_path; } cur_path.clear(); } } if(n <= 100 && m <= 100){ do{ for(int i = 1; i <= cl; i++){ int pos = rnd() % (int)q[i].size(); int x = q[i][pos].first, y = q[i][pos].second; cur_path.push_back(make_pair(x, y)); used[x][y] = true; dfs1(x, y); used[x][y] = false; cur_path.pop_back(); } }while(clock() - begin_t <= 1.0 * CLOCKS_PER_SEC); do{ for(int i = 1; i <= cl; i++){ int pos = rnd() % (int)q[i].size(); int x = q[i][pos].first, y = q[i][pos].second; cur_path.push_back(make_pair(x, y)); used[x][y] = true; dfs2(x, y); used[x][y] = false; cur_path.pop_back(); } }while(clock() - begin_t <= 2.0 * CLOCKS_PER_SEC); do{ for(int i = 1; i <= cl; i++){ int pos = rnd() % (int)q[i].size(); int x = q[i][pos].first, y = q[i][pos].second; cur_path.push_back(make_pair(x, y)); used[x][y] = true; dfs3(x, y); used[x][y] = false; cur_path.pop_back(); } }while(clock() - begin_t <= 3.0 * CLOCKS_PER_SEC); do{ for(int i = 1; i <= cl; i++){ int pos = rnd() % (int)q[i].size(); int x = q[i][pos].first, y = q[i][pos].second; cur_path.push_back(make_pair(x, y)); used[x][y] = true; dfs3(x, y); used[x][y] = false; cur_path.pop_back(); } }while(clock() - begin_t <= 4.8 * CLOCKS_PER_SEC); cout << (int)ans_path.size() << "\n"; for(auto it : ans_path){ cout << it.first << " " << it.second << "\n"; } } else{ do{ for(int i = 1; i <= cl; i++){ int pos = rnd() % (int)q[i].size(); int x = q[i][pos].first, y = q[i][pos].second; cur_path.push_back(make_pair(x, y)); used[x][y] = true; dfs1(x, y); used[x][y] = false; cur_path.pop_back(); } }while(clock() - begin_t <= 1.9 * CLOCKS_PER_SEC); do{ for(int i = 1; i <= cl; i++){ int pos = rnd() % (int)q[i].size(); int x = q[i][pos].first, y = q[i][pos].second; cur_path.push_back(make_pair(x, y)); used[x][y] = true; dfs2(x, y); used[x][y] = false; cur_path.pop_back(); } }while(clock() - begin_t <= 3.8 * CLOCKS_PER_SEC); do{ for(int i = 1; i <= cl; i++){ int pos = rnd() % (int)q[i].size(); int x = q[i][pos].first, y = q[i][pos].second; cur_path.push_back(make_pair(x, y)); used[x][y] = true; dfs3(x, y); used[x][y] = false; cur_path.pop_back(); } }while(clock() - begin_t <= 4.8 * CLOCKS_PER_SEC); cout << (int)ans_path.size() << "\n"; for(auto it : ans_path){ cout << it.first << " " << it.second << "\n"; } }