#include #include #define NUM(A,C,N) (N ? 1 : A) * C #define NODES_O 3 * 5 #define NODES_R 3 * 4 #define NODES_Y 4 * 4 #define NODES_B 3 * 4 #define NODES_G 3 * 4 #define NODES_Z 3 * 4 #define NODES_P 4 * 2 #define NODES_W 3 * 3 #define NUM_O(N) NUM(NODES_O, 45260, N) #define NUM_R(N) NUM(NODES_R, 65236, N) #define NUM_Y(N) NUM(NODES_Y, 259038, N) #define NUM_B(N) NUM(NODES_B, 664608, N) #define NUM_G(N) NUM(NODES_G, 1626, N) #define NUM_Z(N) NUM(NODES_Z, 13666, N) #define NUM_P(N) NUM(NODES_P, 60524, N) #define NUM_W(N) NUM(NODES_W, 68928, N) #define ALL_NUM(N) NUM_O(N) + NUM_R(N) + NUM_Y(N) + NUM_B(N) + NUM_G(N) + NUM_Z(N) + NUM_P(N) + NUM_W(N) const long nr_vecs = ALL_NUM(true) + 8; const long nr_nodes = ALL_NUM(false) + 8 * 96; struct Vector { long up; long down; long piece; long times; long next_removed; long first_node; }; Vector vecs[nr_vecs]; struct Node { long up; long down; long veccol; }; Node nodes[nr_nodes]; #define VEC_AND_COL(V,C) (((V) << 8) | (C)) #define VEC_OF_NODE(N) (nodes[N].veccol >> 8) #define COL_OF_NODE(N) (nodes[N].veccol & 0xFF) struct Piece { long up; long down; long nr_nodes; long first_col_node; long top_vec; long col_left[96]; long left; }; Piece pieces[9] = { { .up = 8, .down = 1, .nr_nodes = NODES_O }, { .up = 0, .down = 2, .nr_nodes = NODES_R }, { .up = 1, .down = 3, .nr_nodes = NODES_Y }, { .up = 2, .down = 4, .nr_nodes = NODES_B }, { .up = 3, .down = 5, .nr_nodes = NODES_G }, { .up = 4, .down = 6, .nr_nodes = NODES_Z }, { .up = 5, .down = 7, .nr_nodes = NODES_P }, { .up = 6, .down = 8, .nr_nodes = NODES_W }, { .up = 7, .down = 0, .nr_nodes = 0 }, }; struct Column { long up; // left long down; // right long left; }; Column columns[97]; #define APPEND(C,H,N) \ {\ long last = C[H].up;\ C[last].down = N;\ C[N].up = last;\ C[N].down = H;\ C[H].up = N;\ } #define REMOVE(C,N) \ C[C[N].up].down = C[N].down;\ C[C[N].down].up = C[N].up; \ #define UNDOREMOVE(C,N) \ C[C[N].up].down = N; \ C[C[N].down].up = N; int count_all = 0; int count_patterns = 0; long count; bool select(Vector *vec) { count = 0; long piece = vec->piece; // remove the piece REMOVE(pieces, vec->piece) // remove the columns for this vector int first_node = vec->first_node; int nr_nodes = pieces[piece].nr_nodes; for (int n = 0; n < nr_nodes; n++) { long col = COL_OF_NODE(first_node + n); REMOVE(columns, col); } // update the nr of vectors left per column for (long col = columns[96].down; col < 96; col = columns[col].down) columns[col].left -= pieces[piece].col_left[col]; long removed_vec = 0; // for all left over pieces for (long p = pieces[8].down; p < 8; p = pieces[p].down) { Piece *piece = &pieces[p]; int piece_nr_nodes = piece->nr_nodes; int piece_first_col_node = piece->first_col_node; int piece_left = piece->left; // for all the columns in the node for (int n = 0; n < nr_nodes; n++) { int col = COL_OF_NODE(first_node + n); // get top node with the colom for this piece long top_node = piece_first_col_node + col; for (long node = nodes[top_node].down; node != top_node; node = nodes[node].down) { if (piece_left == 1) { piece->left = 1; vec->next_removed = removed_vec; return false; } piece_left--; count++; long node_vec = VEC_OF_NODE(node); REMOVE(vecs, node_vec); vecs[node_vec].next_removed = removed_vec; removed_vec = node_vec; long vec_node = vecs[node_vec].first_node; for (long np = 0; np < piece_nr_nodes; np++, vec_node++) { REMOVE(nodes, vec_node); int vec_node_col = COL_OF_NODE(vec_node); --piece->col_left[vec_node_col]; if (--columns[vec_node_col].left == 0) { piece->left = piece_left; vec->next_removed = removed_vec; return false; } } } } piece->left = piece_left; } vec->next_removed = removed_vec; return true; } void unselect(Vector *vec) { for (long removed_vec = vec->next_removed; removed_vec != 0; ) { Vector *other_vec = &vecs[removed_vec]; Piece *piece = &pieces[other_vec->piece]; piece->left++; long piece_nr_nodes = piece->nr_nodes; long vec_node = other_vec->first_node; for (long np = 0; np < piece_nr_nodes; np++, vec_node++) { UNDOREMOVE(nodes, vec_node); int vec_node_col = COL_OF_NODE(vec_node); piece->col_left[vec_node_col]++; columns[vec_node_col].left++; } UNDOREMOVE(vecs, removed_vec); removed_vec = other_vec->next_removed; other_vec->next_removed = 0; } vec->next_removed = 0; Piece *piece = &pieces[vec->piece]; for (long col = columns[96].down; col < 96; col = columns[col].down) columns[col].left += piece->col_left[col]; int first_node = vec->first_node; int nr_nodes = piece->nr_nodes; for (int n = nr_nodes - 1; n >= 0; n--) { int col = COL_OF_NODE(first_node + n); UNDOREMOVE(columns, col); } UNDOREMOVE(pieces, vec->piece) } void solve(int multiply) { long min = -1; int min_col = 0; for (int p = pieces[8].down; p < 8; p = pieces[p].down) if (min == -1 || pieces[p].left < min) { min = pieces[p].left; min_col = 96 + p; } if (min == -1) { // all columns covered count_all += multiply; count_patterns++; fprintf(stdout, " %d", multiply); fflush(stdout); return; } for (int c = columns[96].down; c < 96; c = columns[c].down) if (columns[c].left < min) { min = columns[c].left; min_col = c; } if (min_col >= 96) { Piece *piece = &pieces[min_col - 96]; for (long v = vecs[piece->top_vec].down; v != piece->top_vec; v = vecs[v].down) { Vector *vec = &vecs[v]; if (vec->times == 0) printf(" vtz%ld ", v); if (select(vec)) solve(multiply * vec->times); unselect(vec); } } else { for (int p = pieces[8].down; p < 8; p = pieces[p].down) { long top = pieces[p].first_col_node + min_col; for (long node = nodes[top].down; node != top; node = nodes[node].down) { Vector *vec = &vecs[VEC_OF_NODE(node)]; if (vec->times == 0) printf(" vTz%ld ", VEC_OF_NODE(node)); if (select(vec)) solve(multiply * vec->times); unselect(vec); } } } } void remove_impossible() { for (int p = 0; p < 8; p++) { printf("piece %d\n", p); Piece *piece = &pieces[p]; for (long v = vecs[piece->top_vec].down; v != piece->top_vec; v = vecs[v].down) { bool possible = select(&vecs[v]); unselect(&vecs[v]); if (!possible) printf("vec: %ld %s %ld\n", v, possible ? "pos" : "impos", count); fflush(stdout); } printf("\n"); } } void read_input() { for (int c = 0; c < 97; c++) { columns[c].up = (c + 97 - 1) % 97; columns[c].down = (c + 1) % 97; columns[c].left = 0; } long vec_nr = 0; long node_nr = 0; int cur_piece = -1; char buffer[200]; while (fgets(buffer, 199, stdin)) { if (vec_nr >= nr_vecs) { fprintf(stderr, "ERROR: Too many vecs %ld\n", nr_vecs); exit(1); } int piece = buffer[8] - 'A'; if (piece < 0 || piece >= 8) { fprintf(stderr, "ERROR: Incorect piece for %c\n", buffer[8]); exit(1); } if (piece != cur_piece) { cur_piece = piece; pieces[piece].first_col_node = node_nr; for (int i = 0; i < 96; i++) { pieces[piece].col_left[i] = 0; nodes[node_nr].up = node_nr; nodes[node_nr].down = node_nr; nodes[node_nr].veccol = 0; node_nr++; } pieces[piece].top_vec = vec_nr; vecs[vec_nr].up = vec_nr; vecs[vec_nr].down = vec_nr; vecs[vec_nr].piece = piece; // Not used vecs[vec_nr].times = 0; // Not used vecs[vec_nr].next_removed = 0; // Not used vecs[vec_nr].first_node = 0; // Not used if (vec_nr == 110498) printf("110498: piece %d\n", piece); vec_nr++; for (int i = 0; i < 96; i++) pieces[piece].col_left[i] = 0; pieces[piece].left = 0; } APPEND(vecs, pieces[piece].top_vec, vec_nr); vecs[vec_nr].piece = piece; vecs[vec_nr].times = atoi(buffer); vecs[vec_nr].next_removed = 0; vecs[vec_nr].first_node = node_nr; pieces[piece].left++; for (int i = 0; i < 96; i++) if (buffer[10 + i] == '1') { columns[i].left++; pieces[piece].col_left[i]++; long col_node = pieces[piece].first_col_node + i; APPEND(nodes, col_node, node_nr); nodes[node_nr].veccol = VEC_AND_COL(vec_nr, i); node_nr++; } vec_nr++; } long sum = 0; for (int p = 0; p < 8; p++) { printf("%d: %ld\n", p, pieces[p].left); sum += pieces[p].left; } printf("sum = %ld\n", sum); if (vec_nr != nr_vecs) { fprintf(stderr, "ERROR: nr_vecs %ld %ld\n", vec_nr, nr_vecs); } if (node_nr != nr_nodes) { fprintf(stderr, "ERROR: nr_nodes %ld %ld\n", node_nr, nr_nodes); } } int main(int argc, char *argv[]) { read_input(); //remove_impossible(); solve(1); return 0; }