#pragma GCC optimize ("O3") #pragma GCC target ("tune=native") #pragma GCC target ("avx") #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; /*******************************************************************/ struct Timer { double CYCLE_PER_SEC = 2800000000.0; unsigned long long BEGIN_CYCLE = 0; Timer() {} Timer(double cycle) : CYCLE_PER_SEC(cycle) {} unsigned long long int getCycle() { unsigned int low, high; __asm__ volatile ("rdtsc" : "=a" (low), "=d" (high)); return ((unsigned long long int)low) | ((unsigned long long int)high << 32); } void start(void) { BEGIN_CYCLE = getCycle(); } double get_time(void) { return (double)(getCycle() - BEGIN_CYCLE) / CYCLE_PER_SEC; } } timer; struct XorShift { unsigned int x; XorShift () : x(2463534242U) {} unsigned int rand() { x ^= (x << 13); x ^= (x >> 17); x ^= (x << 5); return x; } } Random; /*******************************************************************/ const double TIME_LIMIT = 0.90; const double TEMP_START = 0.80; const double TEMP_END = 0.001; const double TEMP_DIFF = (TEMP_START - TEMP_END) / TIME_LIMIT; int N,K; int L[500]; bool OriA[60][60]; bool A[60][60]; int CurScore; int BestScore; char Answer[4][500]; char BestAnswer[4][500]; /*******************************************************************/ bool accept (double diff, double temp) { if (diff >= 0) return true; double P = exp(diff / temp) * 4294967295.0; return Random.rand() < P; } int move_rect (int idx, int a2, int b2, int c2, int d2) { int ScoreNxt = 0; for (int x = Answer[0][idx]; x <= Answer[2][idx]; x++) { for (int y = Answer[1][idx]; y <= Answer[3][idx]; y++) { if (!A[x][y]) { ScoreNxt--; } else { ScoreNxt++; } A[x][y] = !A[x][y]; } } for (int x = a2; x <= c2; x++) { for (int y = b2; y <= d2; y++) { if (!A[x][y]) { ScoreNxt--; } else { ScoreNxt++; } } } for (int x = Answer[0][idx]; x <= Answer[2][idx]; x++) { for (int y = Answer[1][idx]; y <= Answer[3][idx]; y++) { A[x][y] = !A[x][y]; } } return ScoreNxt; } void simulated_annealing () { int cnt = 0; while (true) { cnt ++; double cur_time = timer.get_time(); double cur_temp = TEMP_START - TEMP_DIFF * cur_time; if (cur_time > TIME_LIMIT) break; for (int i = 0; i < K; i++) { int rd = Random.rand() & 1; int lx = rd ? 1 : L[i]; int ly = rd ? L[i] : 1; int sx = Random.rand() % (N - lx + 1); int sy = Random.rand() % (N - ly + 1); int diff = move_rect(i, sx, sy, sx + lx - 1, sy + ly - 1); if (accept((double) diff, cur_temp)) { for (int x = Answer[0][i]; x <= Answer[2][i]; x++) { for (int y = Answer[1][i]; y <= Answer[3][i]; y++) { A[x][y] = !A[x][y]; } } for (int x = sx; x < sx + lx; x++) { for (int y = sy; y < sy + ly; y++) { A[x][y] = !A[x][y]; } } Answer[0][i] = sx; Answer[1][i] = sy; Answer[2][i] = sx + lx - 1; Answer[3][i] = sy + ly - 1; CurScore += diff; if (BestScore < CurScore) { BestScore = CurScore; for (int j = 0; j < 4; j++) { copy(Answer[j], Answer[j] + K, BestAnswer[j]); } } } } } cerr << cnt << endl; } void initialize () { for (int i = 0; i < K; i++) { int rd = Random.rand() & 1; int lx = rd ? 1 : L[i]; int ly = rd ? L[i] : 1; int sx = Random.rand() % (N - lx + 1); int sy = Random.rand() % (N - ly + 1); Answer[0][i] = sx; Answer[1][i] = sy; Answer[2][i] = sx + lx - 1; Answer[3][i] = sy + ly - 1; for (int x = sx; x < sx + lx; x++) { for (int y = sy; y < sy + ly; y++) { A[x][y] = !A[x][y]; } } } int cnt_ori = 0, cnt_nxt = 0; for (int x = 0; x < N; x++) { for (int y = 0; y < N; y++) { if (!OriA[x][y]) cnt_ori++; if ( !A[x][y]) cnt_nxt++; } } CurScore = cnt_nxt - cnt_ori; BestScore = CurScore; for (int i = 0; i < 4; i++) { copy(Answer[i], Answer[i] + K, BestAnswer[i]); } } int main () { cin.tie(0); ios::sync_with_stdio(false); timer.start(); cin >> N >> K; for (int i = 0; i < K; i++) { cin >> L[i]; } for (int i = 0; i < N; i++) { string line; cin >> line; for (int j = 0; j < N; j++) { if (line[j] == '1') { OriA[i][j] = A[i][j] = true; } else { OriA[i][j] = A[i][j] = false; } } } initialize(); simulated_annealing(); for (int i = 0; i < K; i++) { for (int j = 0; j < 4; j++) { cout << BestAnswer[j][i] + 1 << (j != 3 ? " " : "\n"); } } cerr << BestScore << endl; return 0; }