#include #define ll long long using namespace std; mt19937 rng(1); const int maxM = 3000000; const clock_t END = 4.8 * CLOCKS_PER_SEC; ///end of execution int N, R; ///matrix dimensions and the number of different block rotations ll a, b, d, e; ///input function parameters int c[maxM + 1], f[maxM + 1]; ///precalculated blocks and rotations const int di[] = {+0, +0, -1, -1, +8, +0, -1, +0, -1, +8, +0, +0, +1, +1, +8, +0, +1, +0, +1, +8, +0, +0, -1, +8, +8, +0, -1, +0, +8, +8, +0, +0, +1, +8, +8, +0, +1, +0, +8, +8, +0, +0, +0, -1, +8, +0, -1, -2, +0, +8, +0, +0, +0, +1, +8, +0, +1, +2, +0, +8, +0, +0, +0, +0, +8, +0, -1, -2, -3, +8, +0, +0, +0, +0, +8, +0, +1, +2, +3, +8, +0, -1, -1, -2, +8, +0, -1, +0, +0, +8, +0, +1, +1, +2, +8, +0, +1, +0, +0, +8}; const int dj[] = {+0, -1, +0, -1, +8, +0, +0, +1, +1, +8, +0, +1, +0, +1, +8, +0, +0, -1, -1, +8, +0, -1, +0, +8, +8, +0, +0, +1, +8, +8, +0, +1, +0, +8, +8, +0, +0, -1, +8, +8, +0, -1, -2, +0, +8, +0, +0, +0, +1, +8, +0, +1, +2, +0, +8, +0, +0, +0, -1, +8, +0, -1, -2, -3, +8, +0, +0, +0, +0, +8, +0, +1, +2, +3, +8, +0, +0, +0, +0, +8, +0, -1, +0, +0, +8, +0, +1, +1, +2, +8, +0, +1, +0, +0, +8, +0, -1, -1, -2, +8}; const int ci[] = {+0, -1, -2, -2, -1, +0, +1, +1, +8, +8, +8, -2, -2, -1, +0, +1, +1, +0, -1, +8, +8, +8, +0, +1, +2, +2, +1, +0, -1, -1, +8, +8, +8, +2, +2, +1, +0, -1, -1, +0, +1, +8, +8, +8, +0, -1, -1, -2, -1, +0, +1, +1, +8, +8, +8, -2, -1, -1, +0, +1, +1, +0, -1, +8, +8, +8, +0, +1, +1, +2, +1, +0, -1, -1, +8, +8, +8, +2, +1, +1, +0, -1, -1, +0, +1, +8, +8, +8, +0, -1, -1, -1, -2, -1, +0, +1, +1, +1, +8, -3, -2, -1, -1, +0, +1, +1, +0, -1, -2, +8, +0, +1, +1, +1, +2, +1, +0, -1, -1, -1, +8, +3, +2, +1, +1, +0, -1, -1, +0, +1, +2, +8, +0, -1, -1, -1, -1, +0, +1, +1, +1, +1, +8, -4, -3, -2, -1, +0, +1, +0, -1, -2, -3, +8, +0, +1, +1, +1, +1, +0, -1, -1, -1, -1, +8, +4, +3, +2, +1, +0, -1, +0, +1, +2, +3, +8, +0, +0, -1, -2, -2, -3, -2, -1, +0, +1, +8, -1, -1, -2, -1, -1, +0, +1, +1, +1, +0, +8, +0, +0, +1, +2, +2, +3, +2, +1, +0, -1, +8, +1, +1, +2, +1, +1, +0, -1, -1, -1, +0, +8}; const int cj[] = {-2, -2, -1, +0, +1, +1, +0, -1, +8, +8, +8, +0, +1, +2, +2, +1, +0, -1, -1, +8, +8, +8, +2, +2, +1, +0, -1, -1, +0, +1, +8, +8, +8, +0, -1, -2, -2, -1, +0, +1, +1, +8, +8, +8, -2, -1, -1, +0, +1, +1, +0, -1, +8, +8, +8, +0, +1, +1, +2, +1, +0, -1, -1, +8, +8, +8, +2, +1, +1, +0, -1, -1, +0, +1, +8, +8, +8, +0, -1, -1, -2, -1, +0, +1, +1, +8, +8, +8, -3, -2, -1, -1, +0, +1, +1, +0, -1, -2, +8, +0, +1, +1, +1, +2, +1, +0, -1, -1, -1, +8, +3, +2, +1, +1, +0, -1, -1, +0, +1, +2, +8, +0, -1, -1, -1, -2, -1, +0, +1, +1, +1, +8, -4, -3, -2, -1, +0, +1, +0, -1, -2, -3, +8, +0, +1, +1, +1, +1, +0, -1, -1, -1, -1, +8, +4, +3, +2, +1, +0, -1, +0, +1, +2, +3, +8, +0, -1, -1, -1, -1, +0, +1, +1, +1, +1, +8, -1, -1, -2, -1, -1, +0, +1, +1, +1, +0, +8, +0, +0, +1, +2, +2, +3, +2, +1, +0, -1, +8, +1, +1, +2, +1, +1, +0, -1, -1, -1, +0, +8, +0, +0, -1, -2, -2, -3, -2, -1, +0, +1, +8}; const int ti[] = {+0, -1, +0, -1, +1, +0, +1, +0, +0, -1, +0, -1, +1, +0, +1, +0, +0, -1, +0, -2, +1, +0, +2, +0, +0, +0, +0, -3, +0, +0, +3, +0, +0, -2, +0, -1, +2, +0, +1, +0}; const int tj[] = {+0, -1, +1, +0, +1, +0, +0, -1, +0, -1, +1, +0, +1, +0, +0, -1, +0, -2, +1, +0, +2, +0, +0, -1, +0, -3, +0, +0, +3, +0, +0, +0, +0, -1, +2, +0, +1, +0, +0, -2}; bool V[31][31]; ///board int rows[31], cols[31]; ///number of set cells of row/column struct DELTA { int cell; ///coordinates denoting the move (hashed (i << 5) + j) int rows, cols; ///bitmasks denoting cleared rows and columns int population, circumference; ///changes in population and circumference }D[maxM + 1]; ///storing board changes within moves int M, SOL[maxM + 1]; ///number of moves and the solution (hashed) char BUFFER[(maxM + 2) * 6]; ///fwrite output buffer inline void CheckpointSystem() ///every time there are no available moves, return to a randomly chosen checkpoint and start over { int iterations = 0; M = 0; int *block = c, *rotation = f; DELTA *delta = D; const int *ipos, *jpos, *cipos, *cjpos; __builtin_memset(V, true, sizeof(V)); for(int i = N + 2; i - 2; i--) __builtin_memset(V[i] + 3, false, N); rows[2] = rows[N + 3] = cols[2] = cols[N + 3] = N; int population = 0, circumference = 4 * N; int flag = (R == 1) && (f[1] < 2); tuple pqr = make_tuple(+5, 20, 10); ///random factor and backtracking parameters determined by N and R if(R == 1) { if(N == +8) pqr = make_tuple(+5, 10, +8); if(N == 16) pqr = make_tuple(+5, 30, 10); if(N == 20) pqr = make_tuple(+3, 50, 10); if(N == 25) pqr = make_tuple(+3, 50, 10); } if(R == 2) { if(N == +8) pqr = make_tuple(+5, 10, +8); if(N == 16) pqr = make_tuple(+5, 20, 10); if(N == 20) pqr = make_tuple(+3, 20, 10); if(N == 25) pqr = make_tuple(+3, 50, 10); } if(R == 4) { if(N == +8) pqr = make_tuple(+5, 10, +8); if(N == 16) pqr = make_tuple(+5, 20, 10); if(N == 20) pqr = make_tuple(10, 20, 10); if(N == 25) pqr = make_tuple(10, 50, 10); } int p = get<0>(pqr), q = get<1>(pqr), r = get<2>(pqr); auto print = [&](bool full = false) ///helper function used for debugging only { cout << M << ":\n"; for(int i = 3; i <= N + 2; i++) { for(int j = 3; j <= N + 2; j++) cout << V[i][j]; cout << '\n'; } if(full) { for(int i = 3; i <= N + 2; i++) cout << rows[i] << " \n"[i == N + 2]; for(int j = 3; j <= N + 2; j++) cout << cols[j] << " \n"[j == N + 2]; cout << population << ' ' << circumference << '\n'; } cout << '\n'; return; }; auto changeMove = [&](const int &sign) ///changes all necessary variables to suit the next or prior move { block += sign, rotation += sign, delta += sign; ipos = di + 5 * ((*block << 2) + *rotation), jpos = dj + 5 * ((*block << 2) + *rotation); cipos = ci + 11 * ((*block << 2) + *rotation), cjpos = cj + 11 * ((*block << 2) + *rotation); return; }; auto rollback = [&](int checkpoint) ///backtracks all variables to the move after checkpoint { int i, j; M--, changeMove(-1); while(M >= checkpoint) { i = delta->cell >> 5, j = delta->cell & 31; if(delta->rows | delta->cols) { for(int i = N + 2; i - 2; i--) { if(!(delta->rows & (1 << i))) {rows[i] += __builtin_popcount(delta->cols); continue;} rows[i] = N; __builtin_memset(V[i] + 3, true, N); } for(int j = N + 2; j - 2; j--) { if(!(delta->cols & (1 << j))) {cols[j] += __builtin_popcount(delta->rows); continue;} cols[j] = N; for(int i = N + 2; i - 2; i--) V[i][j] = true; } } for(const int *ii = ipos, *jj = jpos; *ii - 8; ii++, jj++) { rows[i + *ii]--; cols[j + *jj]--; V[i + *ii][j + *jj] = false; } population -= delta->population; circumference -= delta->circumference; M--, changeMove(-1); } M++, changeMove(+1); return; }; auto getMove = [&](int i, int j) ///calculates changes done by a move, returns whether it's possible { bool RET = true; i += 2, j += 2; for(const int *ii = ipos, *jj = jpos; (*ii - 8) && RET; ii++, jj++) RET ^= V[i + *ii][j + *jj]; if(!RET) return false; *delta = {(i << 5) + j, 0, 0, 0, 0}; for(const int *ii = cipos, *jj = cjpos; *ii - 8; ii++, jj++) delta->circumference += 1 - (V[i + *ii][j + *jj] << 1); for(const int *ii = ipos, *jj = jpos; *ii - 8; ii++, jj++) { delta->population++; rows[i + *ii]++, cols[j + *jj]++; delta->rows |= (rows[i + *ii] == N) << (i + *ii), delta->cols |= (cols[j + *jj] == N) << (j + *jj); } if(!(delta->rows || delta->cols)) { for(const int *ii = ipos, *jj = jpos; *ii - 8; ii++, jj++) rows[i + *ii]--, cols[j + *jj]--; return true; } delta->population -= (__builtin_popcount(delta->rows) + __builtin_popcount(delta->cols)) * N - __builtin_popcount(delta->rows) * __builtin_popcount(delta->cols); int mask, temp; mask = delta->rows; while(mask) { temp = __lg(mask); rows[temp] = 0; delta->circumference += (rows[temp - 1] + rows[temp + 1] - N + 1) << 1; mask ^= 1 << temp; } mask = delta->cols; while(mask) { temp = __lg(mask); cols[temp] = __builtin_popcount(delta->rows); delta->circumference += (cols[temp - 1] + cols[temp + 1] - N - (__builtin_popcount(delta->rows) << 1) + !delta->rows) << 1; mask ^= 1 << temp; } for(const int *ii = ipos, *jj = jpos; *ii - 8; ii++, jj++) { rows[i + *ii] -= bool(delta->rows & (1 << (i + *ii))) * (rows[i + *ii] - N); cols[j + *jj] -= bool(delta->cols & (1 << (j + *jj))) * (cols[j + *jj] - N); } for(const int *ii = ipos, *jj = jpos; *ii - 8; ii++, jj++) rows[i + *ii]--, cols[j + *jj]--; return true; }; auto setMove = [&]() ///physically adds changes contained in *delta { int i = delta->cell >> 5, j = delta->cell & 31; for(const int *ii = ipos, *jj = jpos; *ii - 8; ii++, jj++) { rows[i + *ii]++, cols[j + *jj]++; V[i + *ii][j + *jj] = true; } population += delta->population; circumference += delta->circumference; if(delta->rows || delta->cols) { for(int i = N + 2; i - 2; i--) { if(rows[i] != N) {rows[i] -= __builtin_popcount(delta->cols); continue;} rows[i] = 0; __builtin_memset(V[i] + 3, false, N); } for(int j = N + 2; j - 2; j--) { if(cols[j] != N) {cols[j] -= __builtin_popcount(delta->rows); continue;} cols[j] = 0; for(int i = N + 2; i - 2; i--) V[i][j] = false; } } M++, SOL[M] = delta->cell, changeMove(+1); return; }; auto simulate = [&](int i, int j) ///evaluates the score of move (i, j) with a random factor attached { if(!getMove(i, j)) return INT_MAX; return population * (delta->population >= 0) + delta->population + circumference + delta->circumference - int(rng() % p); }; int best, temp, li, ri, lj, rj; DELTA d; changeMove(+1); while((clock() < END) && (M < maxM)) { iterations++; best = INT_MAX; li = N - *(ti + (((*block << 2) + *rotation) << 1)), ri = *(ti + 1 + (((*block << 2) + *rotation) << 1)); lj = N - *(tj + (((*block << 2) + *rotation) << 1)), rj = *(tj + 1 + (((*block << 2) + *rotation) << 1)); for(int i = li; i + ri; i--) { for(int j = lj; j + rj; j--) { if(V[i + 2][j + 2]) continue; temp = simulate(i, j); if(temp < best) {best = temp + flag; d = *delta;} } } if(best == INT_MAX) {rollback(M - min(int(rng() % q) + r, M)); continue;} *delta = d; setMove(); } cout << "Iterations: " << iterations << '\n'; return; } inline void Input() { freopen("block.in", "r", stdin); ll prev, curr; scanf("%d %lld %lld %d %lld %lld %d", &N, &a, &b, &c[0], &d, &e, &f[0]); prev = c[0]; c[0] %= 5; for(int i = 1; i <= maxM; i++) {prev = curr = (prev ^ a) + b; c[i] = curr % 5;} prev = f[0]; f[0] &= 3; for(int i = 1; i <= maxM; i++) {prev = curr = (prev ^ d) + e; f[i] = curr & 3;} int mask = 0; for(int i = 1; i <= maxM; i++) {R += mask < (mask | (1 << f[i])); mask |= 1 << f[i];} return; } inline void Output() { freopen("block.out", "w", stdout); char *pos = BUFFER; int temp = M; while(temp) {*++pos = temp % 10 + '0'; temp /= 10;} reverse(BUFFER + 1, pos + 1); *++pos = '\n'; for(int i = 1, x, y; i <= M; i++) { x = (SOL[i] >> 5) - 2, y = (SOL[i] & 31) - 2; if(x >= 10) {*++pos = x / 10 + '0'; *++pos = x % 10 + '0';} else *++pos = x + '0'; *++pos = ' '; if(y >= 10) {*++pos = y / 10 + '0'; *++pos = y % 10 + '0';} else *++pos = y + '0'; *++pos = '\n'; } fwrite(BUFFER + 1, 1, pos - BUFFER, stdout); return; } int main() { Input(); cout << "N: " << N << '\n' << "R: " << R << '\n'; CheckpointSystem(); cout << "Moves: " << M << '\n'; Output(); return 0; }