#include #include #include #include #include #include #include #include #include #include #include #include #include #define pb push_back #define mp make_pair #define ll long long #define pii pair #pragma gcc optimize ("O3") #pragma gcc target ("sse4") using namespace std; const char* TASKIN = "path.in"; const char* TASKOUT = "path.out"; const int N = 1e3 + 5; const int MAXV = 1e6 + 5; const int INF = 1e9; const double TL = 3.6; mt19937 mt(313); bool TimeOK() { return clock() < TL * (double)CLOCKS_PER_SEC; } int n, m, MAXL; int a[N][N]; vector nb[MAXV]; int val[MAXV]; int vis[MAXV], vis_iter; int to_vertex(int x, int y) { return (x - 1) * m + y; } pii to_cell(int v) { pii res = {v / m + 1, v % m}; if(res.second == 0) { res.second = m; res.first--; } return res; } int dx[4] = {1, -1, 0, 0}; int dy[4] = {0, 0, 1, -1}; map squish; void input() { for(int i = 0; i < N; i++) for(int j = 0; j < N; j++) a[i][j] = -1; 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(a[i][j] != -1) // squish[a[i][j]]; // int t = 1; // for(map ::iterator it = squish.begin(); it != squish.end(); ++it) // it->second = t++; // for(int i = 1; i <= n; i++) // for(int j = 1; j <= m; j++) // if(a[i][j] != -1) // a[i][j] = squish[a[i][j]]; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { val[to_vertex(i, j)] = a[i][j]; if(a[i][j] == -1) continue; for(int k = 0; k < 4; k++) { if(a[i + dx[k]][j + dy[k]] != -1) nb[to_vertex(i, j)].pb(to_vertex(i + dx[k], j + dy[k])); } } } bool center_cmp(pii x, pii y) { int cx = min(x.first - 1, n - x.first) + min(x.second - 1, m - x.second); int cy = min(y.first - 1, n - y.first) + min(y.second - 1, m - y.second); return cx > cy; } bool val_sort(int x, int y) { if(val[x] != val[y]) return val[x] < val[y]; return x < y; } ll best_score; int ans[MAXV], ans_sz; int source, longest_path, rem_source; int st[MAXV], ptr[MAXV]; int LIS, LDS; int dp_inc[MAXV], dp_dec[MAXV]; int old_LIS[MAXV], old_LDS[MAXV]; pii old_inc[MAXV], old_dec[MAXV]; void add_to_seq(int v) { int low, high, rem; low = 0; high = LIS; rem = 0; while(low <= high) { int mid = (low + high) / 2; if(val[v] > dp_inc[mid]) { rem = mid + 1; low = mid + 1; } else high = mid - 1; } old_LIS[v] = -1; if(rem) { old_LIS[v] = LIS; old_inc[v] = {rem, dp_inc[rem]}; if(rem > LIS) LIS++; dp_inc[rem] = val[v]; } low = 0; high = LDS; rem = 0; while(low <= high) { int mid = (low + high) / 2; if(val[v] < dp_dec[mid]) { rem = mid + 1; low = mid + 1; } else high = mid - 1; } old_LDS[v] = -1; if(rem) { old_LDS[v] = LDS; old_dec[v] = {rem, dp_dec[rem]}; if(rem > LDS) LDS++; dp_dec[rem] = val[v]; } // cerr << "ADDED " << val[v] << " " << LIS << " " << LDS << endl; } void rmv_from_seq(int v) { if(old_LIS[v] != -1) { LIS = old_LIS[v]; dp_inc[old_inc[v].first] = old_inc[v].second; } if(old_LDS[v] != -1) { LDS = old_LDS[v]; dp_dec[old_dec[v].first] = old_dec[v].second; } // cerr << "REMOVED " << val[v] << " " << LIS << " " << LDS << endl; } void DFS(int src) { int top = 1; st[top] = src; LIS = 1, LDS = 1; dp_inc[0] = 0; dp_dec[0] = INF; dp_inc[1] = dp_dec[1] = val[src]; while(top) { if(!TimeOK()) { if(1LL * LIS * LDS > best_score) { best_score = 1LL * LIS * LDS; for(int i = 1; i <= top; i++) ans[i] = st[i]; } return; } int v = st[top]; vis[v] = vis_iter; if(top < MAXL) { if(!nb[v].empty()) { sort(nb[v].begin(), nb[v].end(), val_sort); if(top & 1) reverse(nb[v].begin(), nb[v].end()); } bool go_next = false; for(; ptr[v] < nb[v].size(); ptr[v]++) { int u = nb[v][ptr[v]]; if(vis[u] != vis_iter) { st[++top] = u; add_to_seq(u); go_next = true; break; } } if(go_next) continue; } if(1LL * LIS * LDS > best_score) { best_score = 1LL * LIS * LDS; ans_sz = top; for(int i = 1; i <= top; i++) ans[i] = st[i]; } top--; ptr[v] = 0; rmv_from_seq(v); } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); srand(313); #ifdef ONLINE_JUDGE freopen(TASKIN, "r", stdin); freopen(TASKOUT, "w", stdout); #endif input(); vis_iter++; vector perm; for(int i = 1; i <= n * m; i++) if(val[i] != -1) perm.pb(i); sort(perm.begin(), perm.end(), val_sort); for(int i = 0; i < (int)perm.size() && TimeOK(); i++) { vis_iter++; source = perm[i]; DFS(perm[i]); } #ifndef ONLINE_JUDGE cerr << best_score << endl; #endif // ONLINE_JUDGE cout << ans_sz << endl; for(int i = 1; i <= ans_sz; i++) cout << to_cell(ans[i]).first << " " << to_cell(ans[i]).second << endl; return 0; } /* 3 3 1 3 -1 -1 2 1 -1 1 1 4 */