#include #include #include #include #include using namespace std; #include class Timer{ protected: double startTime; double limit; bool alreadyTimeup; public: Timer(double time_limit){ set(time_limit); } void set(double time_limit){ limit = time_limit; startTime = now(); alreadyTimeup = false; } bool timeup(){ if(alreadyTimeup) return true; if(now() - startTime > limit){ alreadyTimeup = true; return true; }else{ return false; } } double elapse(){ return now() - startTime; } double used(){ return elapse() / limit; } protected: double now(){ timeval tv; gettimeofday(&tv, 0); return tv.tv_sec + tv.tv_usec * 1e-6; } }; #include #include template struct PointBase{ T y, x; PointBase(T y_, T x_):y(y_),x(x_){} PointBase(){} bool operator<(const PointBase& op) const{ if(this->y == op.y) return this->x < op.x; return this->y < op.y; } bool operator==(const PointBase& op) const{ return this->y == op.y && this->x == op.x; } PointBase& operator+=(const PointBase& op){ this->y += op.y; this->x += op.x; return *this; } }; template string to_string(const PointBase& p){ return string("(") + to_string(p.y) + "," + to_string(p.x) + ")"; } template std::ostream& operator<<(std::ostream& os, const PointBase& p) { os << to_string(p); return os; } typedef PointBase Point; template struct BoardBase{ int h, w; vector data; BoardBase(int h_, int w_, const T& init):h(h_),w(w_),data(h * w, init){} void put(Point& p, const T& val){ data[p.y*w + p.x] = val; } void put(int pos, const T& val){ data[pos] = val; } void put(int y, int x, const T& val){ data[y*w + x] = val; } T& get(Point& p){ return data[p.y*w + p.x]; } T& get(int pos){ return data[pos]; } T& get(int y, int x){ return data[y*w + x]; } }; typedef BoardBase Board; typedef long long LL; //* mt19937 randint(123123123); /*/ struct XORShift{ uint32_t operator()(){ static uint32_t x = 123456789, y = 362436069, z = 521288629, w = 88675123; uint32_t t = x ^ (x << 11); x = y; y = z; z = w; return w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); } } randint; //*/ const int N = 60, K = 500; vector L; Timer timer(0.95); double componentCount(uint64_t val, uint64_t val_zero){ uint64_t comp = (val ^ (val<<1)) & val; uint64_t bridge = val_zero & (val >> 1) & (val << 1); return __builtin_popcountll(comp) - __builtin_popcountll(bridge); } double componentCount(vector& vec, vector& vec_zero){ double ans = 0; for(int i = 0; i < N; ++i){ ans += componentCount(vec[i], vec_zero[i]); } return ans; } double componentCount(vector& rows, vector& cols, vector& rows_zero, vector& cols_zero){ return componentCount(rows, rows_zero) + componentCount(cols, cols_zero); } double componentCountDiff(vector& rows, vector& cols, vector& rows_zero, vector& cols_zero, int y, int x){ return componentCount(rows[y], rows_zero[y]) + componentCount(cols[x], cols_zero[x]); } struct State{ vector rows; vector cols; vector assign; vector assign_row; vector row_assign1; vector col_assign1; int score; int last_cur, last_cur2; Point last_p, last_p2; bool last_is_row; State(vector& rows_, vector& cols_) :assign(K), assign_row(K), row_assign1(N, -1), col_assign1(N, -1){ for(int i = 0; i < K; ++i){ if(i % 2 == 0){ assign[i] = Point(randint() % N, 0); assign_row[i] = true; }else{ assign[i] = Point(0, randint() % N); assign_row[i] = false; } } reset(rows_, cols_); } void reset(vector& rows_, vector& cols_){ rows = rows_; cols = cols_; score = 0; for(int cur = 0; cur < K; ++cur){ Point p = assign[cur]; if(assign_row[cur]){ rows[p.y] ^= (1ULL << (p.x+L[cur])) - (1ULL << p.x); }else{ cols[p.x] ^= (1ULL << (p.y+L[cur])) - (1ULL << p.y); } } for(int i = 0; i < N; ++i){ score += __builtin_popcountll(rows[i]); score += __builtin_popcountll(cols[i]); } } vector getRows(){ vector res(N); for(int cur = 0; cur < K; ++cur){ Point p = assign[cur]; if(assign_row[cur]){ res[p.y] ^= (1ULL << (p.x+L[cur])) - (1ULL << p.x); } } return res; } vector getCols(){ vector res(N); for(int cur = 0; cur < K; ++cur){ Point p = assign[cur]; if(!assign_row[cur]){ res[p.x] ^= (1ULL << (p.y+L[cur])) - (1ULL << p.y); } } return res; } void place(int cur, int y, int x, int is_row){ // undo info last_cur = cur; last_p = assign[cur]; last_is_row = assign_row[cur]; // unplace Point p = assign[cur]; if(assign_row[cur]){ score -= __builtin_popcountll(rows[p.y]); rows[p.y] ^= (1ULL << (p.x+L[cur])) - (1ULL << p.x); score += __builtin_popcountll(rows[p.y]); }else{ score -= __builtin_popcountll(cols[p.x]); cols[p.x] ^= (1ULL << (p.y+L[cur])) - (1ULL << p.y); score += __builtin_popcountll(cols[p.x]); } // place if(is_row){ row_assign1[y] = cur; assign[cur] = Point(y, x); assign_row[cur] = true; score -= __builtin_popcountll(rows[y]); rows[y] ^= (1ULL << (x+L[cur])) - (1ULL << x); score += __builtin_popcountll(rows[y]); }else{ col_assign1[x] = cur; assign[cur] = Point(y, x); assign_row[cur] = false; score -= __builtin_popcountll(cols[x]); cols[x] ^= (1ULL << (y+L[cur])) - (1ULL << y); score += __builtin_popcountll(cols[x]); } } void place2(int cur, int y, int x, int cur2, int y2, int x2, int is_row){ place(cur2, y2, x2, is_row); last_cur2 = last_cur; last_p2 = last_p; place(cur, y, x, is_row); } void undo(){ place(last_cur, last_p.y, last_p.x, last_is_row); } void undo2(){ place2(last_cur, last_p.y, last_p.x, last_cur2, last_p2.y, last_p2.x, last_is_row); } vector> getAssign() const{ vector> res(K); for(int i = 0; i < K; ++i){ res[i].first = assign[i]; if(assign_row[i]){ res[i].second = Point(assign[i].y + 1, assign[i].x + L[i]); }else{ res[i].second = Point(assign[i].y + L[i], assign[i].x + 1); } assert(0 <= res[i].first.y && res[i].first.y < N); assert(0 <= res[i].first.x && res[i].first.x < N); assert(0 < res[i].second.y && res[i].second.y <= N); assert(0 < res[i].second.x && res[i].second.x <= N); } return res; } int getScore() const{ return score; } }; int calcScore(vector>& board1, vector>& board2){ int score = 0; for(int y = 0; y < N; ++ y){ for(int x = 0; x < N; ++x){ score += board1[y][x] - board2[y][x]; } } return score; } vector makeTargetRows(vector>& board, vector& cols){ vector rows(N); for(int y = 0; y < N; ++y){ for(int x = 0; x < N; ++x){ if((board[y][x] ^ ((cols[x]>>y)&1)) == 1){ rows[y] |= (1ULL << x); } } } return rows; } vector makeTargetCols(vector>& board, vector& rows){ vector cols(N); for(int y = 0; y < N; ++y){ for(int x = 0; x < N; ++x){ if((board[y][x] ^ ((rows[y]>>x)&1)) == 1){ cols[x] |= (1ULL << y); } } } return cols; } vector> optimize(vector>& board){ vector cols(N); vector rows = makeTargetRows(board, cols); State s(rows, cols); State best_s = s; double threshold_base = 6.0; int threshold = threshold_base; bool is_row = true; LL e = 0; for(; ; ++e){ if((e & 0xfff) == 0xfff){ threshold = threshold_base * (1.0 - timer.used()); if(timer.timeup()) break; if(is_row){ is_row = false; rows = s.getRows(); cols = makeTargetCols(board, rows); s.reset(rows, cols); }else{ is_row = true; cols = s.getCols(); rows = makeTargetRows(board, cols); s.reset(rows, cols); } } int cur = randint() % K; if(s.assign_row[cur] != is_row) continue; int offset = randint() % (N+1 - L[cur]); int idx = randint() % N; if(randint() & 1){ if(is_row){ s.place(cur, idx, offset, true); }else{ s.place(cur, offset, idx, false); } if(s.getScore()-threshold <= best_s.getScore()){ if(s.getScore() < best_s.getScore()){ cerr << "update : " << best_s.getScore() << " -> " << s.getScore() << endl; best_s = s; } }else{ s.undo(); } }else{ int cur2 = -1; if(is_row){ cur2 = s.row_assign1[idx]; }else{ cur2 = s.col_assign1[idx]; } if(cur2 < 0) continue; if(cur == cur2) continue; int offset2 = s.assign[cur].x; if(offset2 + L[cur2] > N) offset2 = randint() % (N+1 - L[cur2]); if(is_row){ s.place2(cur, idx, offset, cur2, s.assign[cur].y, offset2, true); }else{ s.place2(cur, offset, idx, cur2, offset2, s.assign[cur].x, false); } if(s.getScore()-threshold <= best_s.getScore()){ if(s.getScore() < best_s.getScore()){ cerr << "update : " << best_s.getScore() << " -> " << s.getScore() << endl; best_s = s; } }else{ s.undo2(); } } } cerr << "epoch " << e << endl; return best_s.getAssign(); } int main(){ int N_, K_; cin >> N_ >> K_; assert(N == N_ && K == K_); L.resize(K); for(int i = 0; i < K; ++i){ cin >> L[i]; } vector> board(N, vector(N)); for(int y = 0; y < N; ++y){ string s; cin >> s; for(int x = 0; x < N; ++x){ board[y][x] = (s[x] == '1')? 1: 0; } } vector> assign = optimize(board); vector> ans_board = board; for(pair p: assign){ cout << p.first.y+1 << " " << p.first.x+1 << " " << p.second.y << " " << p.second.x << endl; for(int y = p.first.y; y < p.second.y; ++y){ for(int x = p.first.x; x < p.second.x; ++x){ ans_board[y][x] = 1 - ans_board[y][x]; } } } int score = calcScore(board, ans_board); cerr << "Score = " << score << endl; return 0; }