#include #include #include #include #include using namespace std; class Timer { chrono::high_resolution_clock::time_point start, end; double limit; public: Timer() { start = chrono::high_resolution_clock::now(); } Timer(double l) { start = chrono::high_resolution_clock::now(); limit = l; } double getTime() { end = chrono::high_resolution_clock::now(); return chrono::duration(end - start).count(); } bool Over() { if (getTime() > limit) { return true; } return false; } void setLimit(double l) { limit = l; } void setStart() { start = chrono::high_resolution_clock::now(); } double getLimit() { return limit; } }; class Xor128 { unsigned static int x, y, z, w; public: Xor128() { x = 31103110, y = 123456789, z = 521288629, w = 88675123; } unsigned int rand() { unsigned int t; t = (x ^ (x << 11)); x = y; y = z; z = w; return(w = (w ^ (w >> 19)) ^ (t ^ (t >> 8))); } }; unsigned int Xor128::x, Xor128::y, Xor128::z, Xor128::w; const double TIMELIMIT = 0.9; class Solver{ int N, K; int L[500]; char A[60][60]; int sumA0[61][61], sumA1[61][61]; Timer tmr; Xor128 xor128; vector>>ans, best_ans; int best_score; public: void input() { cin >> N >> K; for (int i = 0; i < K; i++)cin >> L[i]; for (int i = 0; i < N; i++)for (int j = 0; j < N; j++) { cin >> A[i][j]; A[i][j] -= '0'; } } void init() { input(); tmr.setStart(); for (int i = 0; i <= N; i++) { for (int j = 0; j <= N; j++) { sumA0[i][j] = sumA1[i][j] = 0; } } for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { sumA0[i + 1][j] += sumA0[i][j] + A[i][j]; sumA1[i][j + 1] += sumA1[i][j] + A[i][j]; } } ans.resize(K, make_pair(-1, make_pair(0, 0))); best_score = 0; for (int i = 0; i < K; i++) { best_score += scoring(0, 0, 0, i); ans[i].first = 0; update(0, 0, 0, i); } best_ans = ans; tmr.setLimit(TIMELIMIT); } void SA() { double startTemp = 1, endTemp = 0.05; double diffTemp = (endTemp - startTemp) / TIMELIMIT; double current_time = tmr.getTime(); int score = best_score; int loop = 0; int i = 0; while (current_time < TIMELIMIT) { loop++; if (loop % 1000 == 0) { current_time = tmr.getTime(); } bool mode = xor128.rand() % 2; int r = xor128.rand() % (N - L[i] + 1); int c = xor128.rand() % N; if (mode)swap(r, c); int change = scoring(mode, r, c, i); bool accept = false; if (change >= 0)accept = true; else if (change < -2)accept = false; else { double temp = startTemp + diffTemp * tmr.getTime(); double prob = exp(change / temp); accept = prob * UINT32_MAX > xor128.rand(); //cerr << tmr.getTime() << endl; /*if (accept) { cerr << change << " " << prob << endl; }*/ } if (accept) { score += change; update(ans[i].first, ans[i].second.first, ans[i].second.second, i); ans[i].first = mode; ans[i].second.first = r; ans[i].second.second = c; update(mode, r, c, i); if (score > best_score) { best_score = score; best_ans = ans; } } i = (i + 1) % K; } cerr << tmr.getTime() << endl; cerr << loop << endl; cerr << best_score << endl; } int scoring(int mode, int r, int c, int i) { int change = 0; if (ans[i].first != -1) { int r = ans[i].second.first; int c = ans[i].second.second; int mode = ans[i].first; if (mode) change += (sumA1[r][c + L[i]] - sumA1[r][c]); else change += (sumA0[r + L[i]][c] - sumA0[r][c]); } if (mode) change += (sumA1[r][c + L[i]] - sumA1[r][c]); else change += (sumA0[r + L[i]][c] - sumA0[r][c]); change -= L[i]; int r1, r2; r1 = r; r2 = ans[i].second.first; int c1, c2; c1 = c; c2 = ans[i].second.second; if (mode == ans[i].first) { if (mode == true && r1 == r2) { if (c1 > c2)swap(c1, c2); if (c1 + L[i] > c2)change += ((c1 + L[i] - c2) - 2 * (sumA1[r][c1 + L[i]] - sumA1[r][c2])); } if (mode == false && c1 == c2) { if (r1 > r2)swap(r1, r2); if (r1 + L[i] > r2)change += ((r1 + L[i] - r2) - 2 * (sumA0[r1 + L[i]][c] - sumA0[r2][c])); } } else if (ans[i].first != -1) { if (mode) { if (c1 <= c2 && c2 <= c1 + L[i] - 1 && r2 <= r1 && r1 <= r2 + L[i] - 1) { change -= (A[r1][c2] ? 1 : -1); } } else { if (r1 <= r2 && r2 <= r1 + L[i] - 1 && c2 <= c1 && c1 <= c2 + L[i] - 1) { change -= (A[r2][c1] ? 1 : -1); } } } change *= 2; if (ans[i].first == -1)change += L[i]; return change; } void update(int mode, int r, int c, int i) { int rev_mode = mode ^ 1; if (mode) { int p = 0; for (int j = c; j < c + L[i]; j++) { if(mode)sumA1[r][j] += p; else sumA0[r][j] += p; int p2 = (A[r][j] ? -1 : 1); for (int k = r + 1; k <= N; k++) { if(rev_mode)sumA1[k][j] += p2; else sumA0[k][j] += p2; } p += (A[r][j] ? -1 : 1); A[r][j] ^= 1; } for (int j = c + L[i]; j <= N; j++) { if (mode)sumA1[r][j] += p; else sumA0[r][j] += p; } } else { int p = 0; for (int j = r; j < r + L[i]; j++) { if (mode)sumA1[j][c] += p; else sumA0[j][c] += p; int p2 = (A[j][c] ? -1 : 1); for (int k = c + 1; k <= N; k++) { if(rev_mode)sumA1[j][k] += p2; else sumA0[j][k] += p2; } p += (A[j][c] ? -1 : 1); A[j][c] ^= 1; } for (int j = r + L[i]; j <= N; j++) { if (mode)sumA1[j][c] += p; else sumA0[j][c] += p; } } } void output() { for (int i = 0; i < K; i++) { cout << best_ans[i].second.first + 1 << " " << best_ans[i].second.second + 1 << " "; if (best_ans[i].first)cout << best_ans[i].second.first + 1 << " " << best_ans[i].second.second + L[i] << endl; else cout << best_ans[i].second.first + L[i] << " " << best_ans[i].second.second + 1 << endl; } } void run() { init(); SA(); output(); } }; int main() { Solver slv; slv.run(); return 0; }