// C++11 #include #include #include #include #include #include #include #include using namespace std; const int64_t CYCLES_PER_SEC = 2600000000; const int N = 60; const int K = 500; struct Timer { int64_t start; Timer() { reset(); } void reset() { start = getCycle(); } void plus(double a) { start -= (a * CYCLES_PER_SEC); } inline double get() { return (double)(getCycle() - start) / CYCLES_PER_SEC; } inline int64_t getCycle() { uint32_t low, high; __asm__ volatile ("rdtsc" : "=a" (low), "=d" (high)); return ((int64_t)low) | ((int64_t)high << 32); } }; class XorShift { public: unsigned int x, y, z, w; double nL[65536]; XorShift() { init(); } void init() { x = 314159265; y = 358979323; z = 846264338; w = 327950288; double n = 1 / (double)(2 * 65536); for (int i = 0; i < 65536; i++) { nL[i] = log(((double)i / 65536) + n); } } inline unsigned int next() { unsigned int t = x ^ x << 11; x = y; y = z; z = w; return w = w ^ w >> 19 ^ t ^ t >> 8; } inline double nextLog() { return nL[next() & 0xFFFF]; } inline int nextInt(int m) { return (int)(next() % m); } int nextInt(int min, int max) { return min + nextInt(max - min + 1); } inline double nextDouble() { return (double)next() / ((long long)1 << 32); } }; //The board is rotated by 90 degrees enum Orientation { VERTICAL, HORIZONTAL }; struct Rectangle { int leftX; int topY; Orientation o; }; struct State { Rectangle rects[K]; int grid[N][N]; void init(int _grid[N][N]) { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { grid[i][j] = _grid[i][j]; } } } int calcScore() { int res = N * N; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { res -= grid[i][j]; } } return res; } int doPlace(int i, int L) { int res = 0; if (rects[i].o == VERTICAL) { int x = rects[i].leftX; for (int y = rects[i].topY; y < rects[i].topY + L; y++) { res += grid[x][y]; grid[x][y] = 1 - grid[x][y]; } } else { int y = rects[i].topY; for (int x = rects[i].leftX; x < rects[i].leftX + L; x++) { res += grid[x][y]; grid[x][y] = 1 - grid[x][y]; } } return res * 2 - L; } int erase(int i, int L) { int res = 0; if (rects[i].o == VERTICAL) { int x = rects[i].leftX; for (int y = rects[i].topY; y < rects[i].topY + L; y++) { res += grid[x][y]; grid[x][y] = 1 - grid[x][y]; } } else { int y = rects[i].topY; for (int x = rects[i].leftX; x < rects[i].leftX + L; x++) { res += grid[x][y]; grid[x][y] = 1 - grid[x][y]; } } return res * 2 - L; } int placeGreedy(int i, int L, XorShift &rnd) { int ones; int mx = -1; int l; int sc; for (int x = 0; x < N; x++) { ones = 0; for (int y = 0; y < L; y++) { ones += grid[x][y]; } l = 0; while (true) { sc = (ones << 12) + (rnd.next() & 0xFFF); if (mx < sc) { mx = sc; rects[i].leftX = x; rects[i].topY = l; rects[i].o = VERTICAL; } if (l + L >= N)break; ones += grid[x][l + L]; ones -= grid[x][l]; l++; } } for (int y = 0; y < N; y++) { ones = 0; for (int x = 0; x < L; x++) { ones += grid[x][y]; } l = 0; while (true) { sc = (ones << 12) + (rnd.next() & 0xFFF); if (mx < sc) { mx = sc; rects[i].leftX = l; rects[i].topY = y; rects[i].o = HORIZONTAL; } if (l + L >= N)break; ones += grid[l + L][y]; ones -= grid[l][y]; l++; } } return doPlace(i, L); } int placeGreedyRange(int i, int L, XorShift &rnd, double range) { int ones; double mx = -1; int l; double sc; int res; for (int x = 0; x < N; x++) { ones = 0; for (int y = 0; y < L; y++) { ones += grid[x][y]; } l = 0; while (true) { sc = ones + range * rnd.nextDouble(); if (mx < sc) { mx = sc; res = ones; rects[i].leftX = x; rects[i].topY = l; rects[i].o = VERTICAL; } if (l + L >= N)break; ones += grid[x][l + L]; ones -= grid[x][l]; l++; } } for (int y = 0; y < N; y++) { ones = 0; for (int x = 0; x < L; x++) { ones += grid[x][y]; } l = 0; while (true) { sc = ones + range * rnd.nextDouble(); if (mx < sc) { mx = sc; res = ones; rects[i].leftX = l; rects[i].topY = y; rects[i].o = HORIZONTAL; } if (l + L >= N)break; ones += grid[l + L][y]; ones -= grid[l][y]; l++; } } doPlace(i, L); return res * 2 - L; } }; class Solver { public: XorShift rnd; Timer timer; //////TASK/////// int grid[N][N]; int L[K]; int L_sorted[K]; int W0; ///////////////// State state; void inputFromStdin() { int _; cin >> _ >> _; for (int i = 0; i < K; i++) { cin >> L[i]; } W0 = N * N; char a; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { cin >> a; grid[i][j] = a - '0'; W0 -= grid[i][j]; } } } void generateTestCase(int seed) { XorShift gen; for (int i = 0; i < 1000; i++) { gen.next(); } for (int i = 0; i < K; i++) { L[i] = gen.nextInt(25) + 1; } sort(L, L + K, greater()); W0 = N * N; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { grid[i][j] = gen.nextInt(2); W0 -= grid[i][j]; } } ofstream ofs("input.txt"); ofs << N << " " << K << endl; for (int i = 0; i < K; i++) { if (i > 0)ofs << " "; ofs << L[i]; } ofs << endl; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { ofs << grid[i][j]; } ofs << endl; } } void outputResult() { int head[25]; for (int i = 0; i < K; i++) { if (i == 0 || L_sorted[i] > L_sorted[i - 1]) { head[L_sorted[i] - 1] = i; } } for (int i = 0; i < K; i++) { Rectangle &r = state.rects[head[L[i] - 1]]; if (r.o == VERTICAL) { cout << r.leftX + 1 << " " << r.topY + 1 << " " << r.leftX + 1 << " " << r.topY + L[i] << endl; } else { cout << r.leftX + 1 << " " << r.topY + 1 << " " << r.leftX + L[i] << " " << r.topY + 1 << endl; } head[L[i] - 1]++; } } void outputDebugInfo() { int W1 = state.calcScore(); cerr << "W0 = " << W0 << ", W1 = " << W1 << endl; cerr << "score = " << W1 - W0 << endl; } void init() { //generateTestCase(0); inputFromStdin(); state.init(grid); for (int i = 0; i < K; i++) { L_sorted[i] = L[i]; } sort(L_sorted, L_sorted + K); } void SA() { int score = state.calcScore(); for (int i = K - 1; i >= 0; i--) { score += state.placeGreedy(i, L_sorted[i], rnd); } /*for (int i = 0; i < K; i++) { score += state.placeGreedy(i, L_sorted[i], rnd); }*/ double ti; int a; int o; int cnt = 0; cerr << score << endl; cerr << state.calcScore() << endl; double di; a = K - 1; double st = timer.get(); cerr << "st=" << st << endl; double timelimit = 0.95; double rem; Rectangle tmp; double T; double T0 = 0.2; int bscore; while (true) { ti = timer.get(); if (ti > timelimit) { break; } rem = (timelimit - ti) / (timelimit - st); T = T0*rem; if (di < ti) { di += 0.1; cerr << score << endl; } cnt++; bscore = score; a = rnd.nextInt(K); score += state.erase(a, L_sorted[a]); tmp = state.rects[a]; o = rnd.nextInt(2); if (o == 0) { state.rects[a].o = VERTICAL; state.rects[a].leftX = rnd.nextInt(N); state.rects[a].topY = rnd.nextInt(N + 1 - L_sorted[a]); } else { state.rects[a].o = HORIZONTAL; state.rects[a].leftX = rnd.nextInt(N + 1 - L_sorted[a]); state.rects[a].topY = rnd.nextInt(N); } score += state.doPlace(a, L_sorted[a]); if (score - bscore > T*rnd.nextLog()) { } else { score += state.erase(a, L_sorted[a]); state.rects[a] = tmp; score+= state.doPlace(a, L_sorted[a]); } } cerr << score << endl; cerr << "cnt = " << cnt << endl; } void greedy() { int score = state.calcScore(); /* for (int i = K - 1; i >= 0; i--) { score += state.placeGreedy(i, L_sorted[i], rnd); }*/ /*for (int i = 0; i < K; i++) { score += state.placeGreedy(i, L_sorted[i], rnd); }*/ double ti; int a; int cnt = 0; cerr << score << endl; cerr << state.calcScore() << endl; double di; a = K - 1; double st = timer.get(); cerr << "st=" << st << endl; double timelimit = 0.95; double rem; int br = 500; int rr; while (true) { ti = timer.get(); if (ti > timelimit) { break; } rem = (timelimit - ti) / (timelimit - st); rr = 350 * rem; if (rr < br) { for (int i = rr; i < br; i++) { score += state.placeGreedy(i, L_sorted[i], rnd); } br = rr; } if (di < ti) { di += 0.1; cerr << score << endl; } cnt++; a = rnd.nextInt(rr, K - 1); //if ((--a) == -1)a = -1; score += state.erase(a, L_sorted[a]); score += state.placeGreedy(a, L_sorted[a], rnd); } cerr << score << endl; cerr << "cnt = " << cnt << endl; } void solve() { init(); greedy(); //SA(); outputDebugInfo(); } }; int main() { Solver solver; solver.solve(); solver.outputResult(); }