#include #if MYDEBUG #include "lib/cp_debug.hpp" #else #define DBG(...) ; #endif using LL = long long; constexpr LL LINF = 334ll << 53; constexpr int INF = 15 << 26; constexpr LL MOD = 1E9 + 7; namespace Problem { using namespace std; struct Rec { int dir, // direction(0,horizontal, 1:vertical), y, x; // coordinate left-upper corner }; uint32_t x = 123456789, y = 362436069, z = 521288629, w = 88675123; uint32_t xor128() { uint32_t t = x ^ (x << 11); x = y; y = z; z = w; return w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); } class Solver { public: int n, k; vector len; vector grid; vector rec, ans; random_device rnd; mt19937 mt; chrono::system_clock::time_point start = chrono::system_clock::now(); Solver(LL n, LL k) : n(n), k(k), len(k), grid(n, 0), rec(k), mt(rnd()){}; void calc_SA() { double temp1 = 0.98, temp2 = 0.99, temp3 = 1.0; int q, d, x, y; int score = -evaluate(grid, rec), max_score; double diff; DBG(score) for (int i = 0; i < k; ++i) { d = xor128() % 2; y = xor128() % n; x = xor128() % (n - len[i] + 1); if (d == 1) swap(x, y); add_rectangle(grid, rec, i, d, y, x); } score += evaluate(grid, rec); max_score = score; ans = rec; DBG(score) int loop = 0; while (!time_limit()) { // cerr << temp3 << ' ' << score << endl; for (int _ = 0; _ < 10000; ++_) { // first q = xor128() % k; x = xor128() % 2 * 2 - 1; if (rec[q].dir == 0) { if (x == -1 and rec[q].x > 0) { diff = (((grid[rec[q].y] >> (rec[q].x - 1)) & 1) + ((grid[rec[q].y] >> (rec[q].x + len[q] - 1)) & 1)) * 2 - 2; if ((double)xor128() / (double)(1ll << 32) < exp(diff / temp1)) { grid[rec[q].y] ^= (1ll << (rec[q].x - 1)); grid[rec[q].y] ^= (1ll << (rec[q].x + len[q] - 1)); rec[q].x--; score += diff; if (score > max_score) { max_score = score; ans = rec; } } } else if (x == 1 and rec[q].x + len[q] < n) { diff = (((grid[rec[q].y] >> (rec[q].x)) & 1) + ((grid[rec[q].y] >> (rec[q].x + len[q])) & 1)) * 2 - 2; if ((double)xor128() / (double)(1ll << 32) < exp(diff / temp1)) { grid[rec[q].y] ^= (1ll << (rec[q].x)); grid[rec[q].y] ^= (1ll << (rec[q].x + len[q])); rec[q].x++; score += diff; if (score > max_score) { max_score = score; ans = rec; } } } } else { if (x == -1 and rec[q].y > 0) { diff = (((grid[rec[q].y - 1] >> (rec[q].x)) & 1) + ((grid[rec[q].y + len[q] - 1] >> (rec[q].x)) & 1)) * 2 - 2; if ((double)xor128() / (double)(1ll << 32) < exp(diff / temp1)) { grid[rec[q].y - 1] ^= (1ll << rec[q].x); grid[rec[q].y + len[q] - 1] ^= (1ll << rec[q].x); rec[q].y--; score += diff; if (score > max_score) { max_score = score; ans = rec; } } } else if (x == 1 and rec[q].y + len[q] < n) { diff = (((grid[rec[q].y] >> (rec[q].x)) & 1) + ((grid[rec[q].y + len[q]] >> (rec[q].x)) & 1)) * 2 - 2; if ((double)xor128() / (double)(1ll << 32) < exp(diff / temp1)) { grid[rec[q].y] ^= (1ll << rec[q].x); grid[rec[q].y + len[q]] ^= (1ll << rec[q].x); rec[q].y++; score += diff; if (score > max_score) { max_score = score; ans = rec; } } } } // second : swap the length of two rectangles q = xor128() % k; do { d = xor128() % k; } while (rec[d].dir != rec[q].dir or (rec[d].dir == 0 and rec[q].y == rec[d].y) or (rec[d].dir == 1 and rec[q].x == rec[d].x)); if (len[q] < len[d]) swap(q, d); diff = -2 * (len[q] - len[d]); if (len[q] > len[d]) { if (rec[d].dir == 0 and rec[d].x + len[q] <= n) { LL mask = (1ll << len[q]) - (1ll << len[d]); diff += __builtin_popcountll((mask << rec[q].x) & grid[rec[q].y]) * 2; diff += __builtin_popcountll((mask << rec[d].x) & grid[rec[d].y]) * 2; if ((double)xor128() / (double)(1ll << 32) < exp(diff / temp2)) { score += diff; grid[rec[q].y] ^= (mask << rec[q].x); grid[rec[d].y] ^= (mask << rec[d].x); swap(rec[q], rec[d]); if (score > max_score) { max_score = score; ans = rec; } } } else if (rec[d].dir == 1 and rec[d].y + len[q] <= n) { for (int l = len[d]; l < len[q]; ++l) { diff += ((grid[rec[q].y + l] >> (rec[q].x)) & 1) << 1; diff += ((grid[rec[d].y + l] >> (rec[d].x)) & 1) << 1; } if ((double)xor128() / (double)(1ll << 32) < exp(diff / temp2)) { score += diff; for (int l = len[d]; l < len[q]; ++l) { grid[rec[q].y + l] ^= (1ll << rec[q].x); grid[rec[d].y + l] ^= (1ll << rec[d].x); } swap(rec[q], rec[d]); if (score > max_score) { max_score = score; ans = rec; } } } } // third loop++; q = xor128() % k; d = xor128() % 2; y = xor128() % n; x = xor128() % (n - len[q] + 1); if (d == 1) swap(x, y); auto tmp = rec[q]; diff = remove_rectangle(grid, rec, q) + add_rectangle(grid, rec, q, d, y, x); if ((double)xor128() / (double)(1ll << 32) < exp(diff / temp3)) { // DBG(score, diff) score += diff; if (score > max_score) { max_score = score; ans = rec; } } else { remove_rectangle(grid, rec, q); add_rectangle(grid, rec, q, tmp.dir, tmp.y, tmp.x); } } DBG(temp1, score) temp3 = update_temperature(); temp2 = 1.0 / (1.0 / temp3 + 0.004); temp1 = 1.0 / (1.0 / temp2 + 0.004); // temp2 = temp3 - pow(temp3, 2.01); // temp1 = temp2 - pow(temp2, 2.02); } cerr << max_score << endl; cerr << loop << endl; } int evaluate(vector& gr, vector& r) { int ret = n * n; for (int i = 0; i < n; ++i) { ret -= __builtin_popcountll(gr[i]); } return ret; } int remove_rectangle(vector& gr, vector& r, int i) { int ret = 0; int yy = r[i].y; int xx = r[i].x; if (r[i].dir == 1) { for (int j = 0; j < len[i]; ++j) { ret += ((gr[yy] >> xx) & 1); gr[yy] ^= (1ll << xx); yy++; } } else { LL mask = (1ll << (xx + len[i])) - (1ll << xx); ret += __builtin_popcountll(mask & gr[yy]); gr[yy] ^= mask; } return 2 * ret - len[i]; } int add_rectangle(vector& gr, vector& r, int i, int dir, int y, int x) { r[i] = {dir, y, x}; int ret = 0; if (dir == 1) { for (int j = 0; j < len[i]; ++j) { ret += ((gr[y] >> x) & 1); gr[y] ^= (1ll << x); y++; } } else { LL mask = (1ll << (x + len[i])) - (1ll << x); ret += __builtin_popcountll(mask & gr[y]); gr[y] ^= mask; } return 2 * ret - len[i]; } void input() { for (int i = 0; i < k; ++i) { cin >> len[i]; } int tmp = 0; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { char tmp; cin >> tmp; grid[i] += ((LL)(tmp - '0') << j); } tmp += __builtin_popcountll(grid[i]); } DBG(tmp) } void output() { for (int i = 0; i < k; ++i) { if (ans[i].dir == 0) { cout << ans[i].y + 1 << ' ' << ans[i].x + 1 << ' ' << ans[i].y + 1 << ' ' << ans[i].x + len[i] << "\n"; } else { cout << ans[i].y + 1 << ' ' << ans[i].x + 1 << ' ' << ans[i].y + len[i] << ' ' << ans[i].x + 1 << "\n"; } } } void solve() { input(); // randomize initial state uniform_int_distribution seed(0, 100); int loop = seed(mt); for (int i = 0; i < loop; ++i) { xor128(); } calc_SA(); output(); } bool time_limit(double thres = 0.97 * 1) { double t = chrono::duration_cast( chrono::system_clock::now() - start) .count() / 1000.0; #if MYDEBUG thres *= 2.4; #else ; #endif return t > thres; } double update_temperature() { double t_left = (1000 - chrono::duration_cast( chrono::system_clock::now() - start) .count()); #if MYDEBUG t_left = (2400 - chrono::duration_cast( chrono::system_clock::now() - start) .count()) / 2.4; #else ; #endif t_left /= 1000; // return 0.8 * pow(t_left, 0.8) * exp((t_left - 1) * 1); return 0.8 * exp((t_left - 1) * 2.4) * pow(t_left, 1) * ((t_left * (1 - t_left) * (1 - t_left) * 4 + 1)) + t_left * (1 - t_left) * (1 - t_left) * (1 - t_left) * 1.5; // return t_left/2+0.02; } }; // namespace Problem } // namespace Problem int main() { std::cin.tie(0); std::ios_base::sync_with_stdio(false); long long n = 0, k; std::cin >> n >> k; Problem::Solver sol(n, k); sol.solve(); return 0; }