#include <cstdio> #include <cstdlib> #include <cctype> #include <cstdint> #include <algorithm> #include <array> #include <bit> #include <numeric> #include <vector> struct seq_stat { uint64_t bitmap = 0; bool done = false; std::array<uint64_t, 'Z' - 'A' + 1> letter_counts; void inc_letter(char c) { c -= 'A'; ++letter_counts[c]; bitmap |= 1 << c; } void dec_letter(char c) { c -= 'A'; if (letter_counts[c] > 0) { if (--letter_counts[c] == 0) { bitmap &= ~(1 << c); } } } bool can_be_filled() const { return !is_done() && std::popcount(bitmap) == 1; } char char_to_fill() const { return 'A' + std::countr_zero(bitmap); } void mark_as_done() { done = true; } bool is_done() const { return done; } }; enum class op_type { del_row, del_col }; struct operation { op_type typ; int position; char fill; }; int main() { int h, w; scanf("%d %d", &h, &w); std::vector<seq_stat> cols, rows; cols.resize(w); rows.resize(h); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { int c; while (std::isspace(c = getchar())) {} cols[x].inc_letter(c); rows[y].inc_letter(c); } } std::vector<operation> ops; for (int y = 0; y < h; y++) { if (rows[y].can_be_filled()) { ops.push_back({op_type::del_row, y, rows[y].char_to_fill()}); rows[y].mark_as_done(); } } for (int x = 0; x < w; x++) { if (cols[x].can_be_filled()) { ops.push_back({op_type::del_col, x, cols[x].char_to_fill()}); cols[x].mark_as_done(); } } size_t current_op = 0; while (current_op < ops.size()) { const auto [typ, which, letter] = ops[current_op++]; switch (typ) { case op_type::del_col: { for (int y = 0; y < h; y++) { if (rows[y].is_done()) { continue; } rows[y].dec_letter(letter); if (rows[y].can_be_filled()) { ops.push_back({op_type::del_row, y, rows[y].char_to_fill()}); rows[y].mark_as_done(); } } } break; case op_type::del_row: { for (int x = 0; x < w; x++) { if (cols[x].is_done()) { continue; } cols[x].dec_letter(letter); if (cols[x].can_be_filled()) { ops.push_back({op_type::del_col, x, cols[x].char_to_fill()}); cols[x].mark_as_done(); } } } break; } } std::reverse(ops.begin(), ops.end()); printf("%d\n", (int)ops.size()); for (const auto& [typ, which, letter] : ops) { printf("%c %d %c\n", typ == op_type::del_col ? 'K' : 'R', which + 1, letter); } return 0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | #include <cstdio> #include <cstdlib> #include <cctype> #include <cstdint> #include <algorithm> #include <array> #include <bit> #include <numeric> #include <vector> struct seq_stat { uint64_t bitmap = 0; bool done = false; std::array<uint64_t, 'Z' - 'A' + 1> letter_counts; void inc_letter(char c) { c -= 'A'; ++letter_counts[c]; bitmap |= 1 << c; } void dec_letter(char c) { c -= 'A'; if (letter_counts[c] > 0) { if (--letter_counts[c] == 0) { bitmap &= ~(1 << c); } } } bool can_be_filled() const { return !is_done() && std::popcount(bitmap) == 1; } char char_to_fill() const { return 'A' + std::countr_zero(bitmap); } void mark_as_done() { done = true; } bool is_done() const { return done; } }; enum class op_type { del_row, del_col }; struct operation { op_type typ; int position; char fill; }; int main() { int h, w; scanf("%d %d", &h, &w); std::vector<seq_stat> cols, rows; cols.resize(w); rows.resize(h); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { int c; while (std::isspace(c = getchar())) {} cols[x].inc_letter(c); rows[y].inc_letter(c); } } std::vector<operation> ops; for (int y = 0; y < h; y++) { if (rows[y].can_be_filled()) { ops.push_back({op_type::del_row, y, rows[y].char_to_fill()}); rows[y].mark_as_done(); } } for (int x = 0; x < w; x++) { if (cols[x].can_be_filled()) { ops.push_back({op_type::del_col, x, cols[x].char_to_fill()}); cols[x].mark_as_done(); } } size_t current_op = 0; while (current_op < ops.size()) { const auto [typ, which, letter] = ops[current_op++]; switch (typ) { case op_type::del_col: { for (int y = 0; y < h; y++) { if (rows[y].is_done()) { continue; } rows[y].dec_letter(letter); if (rows[y].can_be_filled()) { ops.push_back({op_type::del_row, y, rows[y].char_to_fill()}); rows[y].mark_as_done(); } } } break; case op_type::del_row: { for (int x = 0; x < w; x++) { if (cols[x].is_done()) { continue; } cols[x].dec_letter(letter); if (cols[x].can_be_filled()) { ops.push_back({op_type::del_col, x, cols[x].char_to_fill()}); cols[x].mark_as_done(); } } } break; } } std::reverse(ops.begin(), ops.end()); printf("%d\n", (int)ops.size()); for (const auto& [typ, which, letter] : ops) { printf("%c %d %c\n", typ == op_type::del_col ? 'K' : 'R', which + 1, letter); } return 0; } |