#include #include #include #include #include #include #include using namespace std; #define U(v) cerr << #v << ": " << (v) << endl constexpr int dx[] = { 1, 0, -1, 0 }; constexpr int dy[] = { 0, 1, 0, -1 }; class timer { vector timers; int n = 0; public: double limit = 0.98; double t = 0; timer() {} timer(int size) : timers(size) {} bool elapses() const { return time() - t > limit; } void measure() { t = time() - t; ++n; } void measure(char id) { timers[id].measure(); } void print() { if (n % 2) measure(); for (int i = 0; i < 128; ++i) { if (timers[i].n) cerr << (char)i << ' ' << timers[i].t << 's' << endl; } cerr << " " << t << 's' << endl; } static double time() { #ifdef LOCAL return __rdtsc() / 3.3e9; #else return chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count() / 1000.0; #endif } } timer(128); class { //unsigned y = 2463534242; unsigned y = random_device()(); public: unsigned next() { return y ^= (y ^= (y ^= y << 13) >> 17) << 5; } int next(int b) { return next() % b; } int next(int a, int b) { return next(b - a) + a; } double nextDouble(double b = 1) { return b * next() / 4294967296.0; } double nextDouble(double a, double b) { return nextDouble(b - a) + a; } int operator() (int b) { return next(b); } } rando; struct Rectangle { bool vertical; char x, y, length; short id; Rectangle() {} Rectangle(bool vertical, char x, char y, char length, short id) : vertical(vertical), x(x), y(y), length(length), id(id) {} }; constexpr int N = 60; constexpr int K = 500; int L[K]; bool A[N][N]; unsigned long long board[2][N]; vector states, bestStates; int score, bestScore; vector p2i[2][N]; inline void flip(const Rectangle& r) { board[r.vertical][r.y] ^= ((1ull << r.length) - 1) << r.x; unsigned long long mask = 1ull << r.y; for (int x = r.x; x < r.x + r.length; ++x) board[!r.vertical][x] ^= mask; } inline void flip2(const Rectangle& r, int i) { board[r.vertical][r.y] ^= ((1ull << r.length) - 1) << r.x; if ((unsigned)i - r.x < (unsigned)r.length) board[!r.vertical][i] ^= 1ull << r.y; } int main(int argc, char** argv) { timer.measure(); { int k; cin >> k >> k; for (int i = 0; i < K; ++i) cin >> L[i]; char s[N + 1]; for (int y = 0; y < N; ++y) { cin >> s; for (int x = 0; x < N; ++x) A[y][x] = s[x] == '1'; } } for (int y = 0; y < N; ++y) { for (int x = 0; x < N; ++x) { if (A[y][x]) { board[0][y] |= 1ull << x; board[1][x] |= 1ull << y; } else { --score; } } } vector a1, a2; { pair a[K]; for (int i = 0; i < K; ++i) a[i] = { L[i], i }; sort(rbegin(a), rend(a)); for (auto& p : a) { if (p.first > 2) { long long b = -1 << 30; array n; for (int i = 0; i < 2; ++i) { for (int y = 0; y < N; ++y) { for (int x = 0; x < N - p.first + 1; ++x) { long long s = __builtin_popcountll(board[i][y] & ((1ull << p.first) - 1) << x); if (b < s) { b = s; n = { i, x, y }; } } } } p2i[n[0]][n[2]].emplace_back((int)states.size()); states.emplace_back(!!n[0], n[1], n[2], p.first, p.second); flip(states.back()); } else { (p.first == 1 ? a1 : a2).emplace_back(p.second); score += p.first; } } } for (int y = 0; y < N; ++y) score += N - (int)__builtin_popcountll(board[0][y]); bestScore = score; bestStates = states; double heat = 0; for (int iter = -1; ; ) { if ((++iter & 0x1ff) == 0) { //double p = 1 - iter / 1000000.0; double p = 1 - (timer.time() - timer.t) / timer.limit; if (p < 0) { //U(iter); break; } constexpr double InitialHeat = 0.7; constexpr double FinalHeat = 1e-9; heat = 1 / (p * (InitialHeat - FinalHeat) + FinalHeat); } pair a[2]{ { !(rando.next() & 1), rando.next(N) } }; do { a[1] = { !(rando.next() & 1), rando.next(N) }; } while (a[0] == a[1]); if (a[0].first) swap(a[0], a[1]); bool par = a[0].first == a[1].first; int curr = (int)__builtin_popcountll(board[a[0].first][a[0].second]) + (int)__builtin_popcountll(board[a[1].first][a[1].second]) - (!par && board[a[0].first][a[0].second] >> a[1].second & 1); static vector is; static vector rs; is.clear(); rs.clear(); for (int h = 0; h < 2; ++h) { auto& p = a[h]; for (int i : p2i[p.first][p.second]) { is.emplace_back(i); flip2(states[i], par ? -1 : a[1 - h].second); } } random_shuffle(is.begin(), is.end(), rando); for (int i : is) { auto& r = states[i]; long long b = -1 << 30; pair bp; int bx; for (auto& p : a) { unsigned long long bi = board[p.first][p.second]; unsigned long long ma = (1ull << r.length) - 1; for (int x = 0; x < N - r.length + 1; ++x) { long long s = __builtin_popcountll(bi & ma); if (b < s) { b = s; bp = p; bx = x; if (b == r.length) break; } bi >>= 1; } if (b == r.length) break; } rs.emplace_back(bp.first, bx, bp.second, r.length, r.id); flip2(rs.back(), par ? -1 : a[!bp.first].second); } for (int last = -1; ; ) { bool updated = false; for (int h = 0; h < (int)rs.size(); ++h) { auto& r = rs[h]; long long c = board[r.vertical][r.y] & ((1ull << r.length) - 1) << r.x; if (c == 0) continue; flip2(r, par ? -1 : a[!r.vertical].second); long long b = c = r.length - __builtin_popcountll(c); pair bp; int bx; for (auto& p : a) { unsigned long long bi = board[p.first][p.second]; unsigned long long ma = (1ull << r.length) - 1; for (int x = 0; x < N - r.length + 1; ++x) { long long s = __builtin_popcountll(bi & ma); if (b < s) { b = s; bp = p; bx = x; } bi >>= 1; } } if (b != c) { last = h; updated = true; r.vertical = bp.first; r.x = bx; r.y = bp.second; } else if (last == h) { flip2(r, par ? -1 : a[!r.vertical].second); break; } flip2(r, par ? -1 : a[!r.vertical].second); } if (!updated) break; } int diff = curr - ((int)__builtin_popcountll(board[a[0].first][a[0].second]) + (int)__builtin_popcountll(board[a[1].first][a[1].second]) - (!par && board[a[0].first][a[0].second] >> a[1].second & 1)); if (rando.nextDouble() < exp(diff * heat)) { score += diff; for (int i = 0; i < (int)is.size(); ++i) { { auto& r = states[is[i]]; unsigned long long mask = 1ull << r.y; if (!par && (unsigned)a[!r.vertical].second - r.x < (unsigned)r.length) board[!r.vertical][a[!r.vertical].second] ^= mask; for (int x = r.x; x < r.x + r.length; ++x) board[!r.vertical][x] ^= mask; } { auto& r = rs[i]; unsigned long long mask = 1ull << r.y; if (!par && (unsigned)a[!r.vertical].second - r.x < (unsigned)r.length) board[!r.vertical][a[!r.vertical].second] ^= mask; for (int x = r.x; x < r.x + r.length; ++x) board[!r.vertical][x] ^= mask; } } for (auto& p : a) p2i[p.first][p.second].clear(); for (int i = 0; i < (int)is.size(); ++i) { states[is[i]] = rs[i]; p2i[rs[i].vertical][rs[i].y].emplace_back(is[i]); } if (bestScore < score) { bestScore = score; bestStates = states; } } else { for (int i = 0; i < (int)is.size(); ++i) { flip2(states[is[i]], par ? -1 : a[!states[is[i]].vertical].second); flip2(rs[i], par ? -1 : a[!rs[i].vertical].second); } } } score = bestScore; states.swap(bestStates); for (auto& r : states) { if (r.vertical) { for (int x = r.x; x < r.x + r.length; ++x) A[x][r.y] ^= 1; } else { for (int x = r.x; x < r.x + r.length; ++x) A[r.y][x] ^= 1; } } for (int y = 0; y < N; ++y) { for (int x = 0; x < N; ++x) { if (y && A[y][x] && A[y - 1][x] && a2.size()) { A[y][x] = A[y - 1][x] = false; states.emplace_back(true, y - 1, x, 2, a2.back()); a2.pop_back(); } if (x && A[y][x] && A[y][x - 1] && a2.size()) { A[y][x] = A[y][x - 1] = false; states.emplace_back(false, x - 1, y, 2, a2.back()); a2.pop_back(); } } } for (int y = 0; y < N; ++y) { for (int x = 0; x < N; ++x) { if (A[y][x]) continue; for (int i = 1; i < 4; ++i) { int x2 = x + dx[i]; int y2 = y + dy[i]; if (x2 < 0 || N <= x2 || y2 < 0 || N <= y2 || !A[y2][x2]) continue; for (int j = 0; j < i; ++j) { int x3 = x + dx[j]; int y3 = y + dy[j]; if (x3 < 0 || N <= x3 || y3 < 0 || N <= y3 || !A[y3][x3] || a2.size() < 2) continue; A[y2][x2] = A[y3][x3] = false; score -= 2; if (i % 2) states.emplace_back(true, min(y, y2), x, 2, a2.back()); else states.emplace_back(false, min(x, x2), y, 2, a2.back()); a2.pop_back(); if (j % 2) states.emplace_back(true, min(y, y3), x, 2, a2.back()); else states.emplace_back(false, min(x, x3), y, 2, a2.back()); a2.pop_back(); break; } } } } score -= (int)a2.size() * 2; for (int y = 0; y < N && a2.size(); ++y) { for (int x = 0; x < N && a2.size(); ++x) { if (y && A[y][x] != A[y - 1][x]) { for (; a2.size(); a2.pop_back()) { A[y][x] ^= 1; A[y - 1][x] ^= 1; states.emplace_back(true, y - 1, x, 2, a2.back()); } } if (x && A[y][x] != A[y][x - 1]) { for (; a2.size(); a2.pop_back()) { A[y][x] ^= 1; A[y][x - 1] ^= 1; states.emplace_back(false, x - 1, y, 2, a2.back()); } } } } for (int y = 0; y < N; ++y) { for (int x = 0; x < N; ++x) { if (A[y][x] && a1.size()) { states.emplace_back(false, x, y, 1, a1.back()); a1.pop_back(); } } } sort(states.begin(), states.end(), [](const Rectangle& a, const Rectangle& b) { return a.id < b.id; }); for (auto& r : states) { if (r.vertical) { cout << r.x + 1 << ' ' << r.y + 1 << ' ' << r.x + r.length << ' ' << r.y + 1 << endl; } else { cout << r.y + 1 << ' ' << r.x + 1 << ' ' << r.y + 1 << ' ' << r.x + r.length << endl; } } return 0; }