#include #include #include #include #include #include #define For(x) for (int it = 0; it < x; it++) using namespace std; string Text; int CostCL, CostCR, CostW, CostCD, CostStack; int CostK[27]; struct node { node* Prev = 0; node* Next = 0; char Value = 0; }; struct state { node Nodes[27]{}; node* Rows[27]{}; node* Stack; int ActiveRow; string Out; int AccumCost; }; struct instruction { enum type { CYCLE_LEFT, CYCLE_RIGHT, WRITE, CHANGE_ACTIVE_ROW, PUSH, POP }; type Type; union { int Count; // If WRITE int Index; // If CHANGE_ACTIVE_ROW }; }; char index_to_char(int index) { assert(index >= 0 && index <= 26); if (index == 26) return '_'; else return 'a' + index; } int char_to_index(char value) { assert((value >= 'a' && value <= 'z') || value == '_'); if (value == '_') return 26; else return value - 'a'; } void insert_begin(node** start, node* n) { if (!(*start)) { n->Prev = n; n->Next = n; } else { node* last = (*start)->Prev; n->Next = *start; n->Prev = last; last->Next = (*start)->Prev = n; } *start = n; } node* pop_begin(node** start) { node* n = *start; if (n->Next == n) { *start = 0; } else { node* last = (*start)->Prev; last->Next = n->Next; n->Next->Prev = last; *start = n->Next; } return n; } void initialize_state(state* st, const string& stateText) { int n; auto s = istringstream(stateText); s >> n; For(n) { string row; s >> row; st->Rows[it] = 0; for (int i = (int)row.size() - 1; i >= 0; i--) { insert_begin(&st->Rows[it], &st->Nodes[char_to_index(row[i])]); } } st->AccumCost = 0; st->ActiveRow = 0; st->Stack = 0; st->Out.clear(); } void initialize_dumb_state(state* s) { For(27) { s->Nodes[it].Value = index_to_char(it); } For(27) { auto* n = &s->Nodes[it]; s->Rows[it] = n; n->Next = n; n->Prev = n; } s->AccumCost = 0; s->ActiveRow = 0; s->Stack = 0; s->Out.clear(); } void interpret(state* s, const vector& instructions) { For(instructions.size()) { node** row = &s->Rows[s->ActiveRow]; auto& i = instructions[it]; switch (i.Type) { case instruction::CYCLE_LEFT: *row = (*row)->Next; s->AccumCost += CostCL; break; case instruction::CYCLE_RIGHT: *row = (*row)->Prev; s->AccumCost += CostCR; break; case instruction::WRITE: { int cost = 0; For(i.Count) { s->Out.push_back((*row)->Value); *row = (*row)->Next; cost += CostW / (it + 1); } s->AccumCost += cost; break; } case instruction::CHANGE_ACTIVE_ROW: assert(i.Index >= 0 && i.Index < 27); s->ActiveRow = i.Index; s->AccumCost += CostCD; break; case instruction::PUSH: { node* n = pop_begin(row); n->Prev = s->Stack; n->Next = 0; if (s->Stack) s->Stack->Next = n; s->Stack = n; s->AccumCost += CostStack; break; } case instruction::POP: { assert(s->Stack); auto* n = s->Stack; s->Stack = n->Prev; insert_begin(row, n); s->AccumCost += CostStack; break; } } } } vector generate_obvious_instructions(const string& text) { vector result; result.reserve(text.size() * 2); for (auto ch : text) { instruction i; i.Type = instruction::CHANGE_ACTIVE_ROW; i.Index = char_to_index(ch); result.push_back(i); i.Type = instruction::WRITE; i.Count = 1; result.push_back(i); } return result; } vector read_instructions(const string& instructions) { vector result; int n; auto s = istringstream(instructions); s >> n; result.reserve(n); For(n) { string op; s >> op; instruction i; if (op == "cl") i.Type = instruction::CYCLE_LEFT; else if (op == "cr") i.Type = instruction::CYCLE_RIGHT; else if (op == "push") i.Type = instruction::PUSH; else if (op == "pop") i.Type = instruction::POP; else if (op == "w") { i.Type = instruction::WRITE; s >> i.Count; } else if (op == "cd") { i.Type = instruction::CHANGE_ACTIVE_ROW; s >> i.Index; i.Index -= 1; } result.push_back(i); } return result; } string print_state(state* st, int usedRows) { auto s = ostringstream(); s << usedRows << '\n'; For(usedRows) { auto* n = st->Rows[it]; s << n->Value; auto* i = n->Next; while (i != n) { s << i->Value; i = i->Next; } s << '\n'; } return s.str(); } string print_instructions(const vector& instructions) { auto s = ostringstream(); s << instructions.size() << '\n'; for (auto& i : instructions) { if (i.Type == instruction::CYCLE_LEFT) s << "cl"; else if (i.Type == instruction::CYCLE_RIGHT) s << "cr"; else if (i.Type == instruction::PUSH) s << "push"; else if (i.Type == instruction::POP) s << "pop"; else if (i.Type == instruction::WRITE) s << "w " << i.Count; else if (i.Type == instruction::CHANGE_ACTIVE_ROW) s << "cd " << (i.Index + 1); s << '\n'; } return s.str(); } int main() { int n; auto file = ifstream("printing.in"); auto fileOut = ofstream("printing.out"); if (file.is_open() && fileOut.is_open()) { file >> n >> Text; file >> CostCL >> CostCR >> CostW >> CostCD >> CostStack; For(27) { file >> CostK[it]; } state s; initialize_dumb_state(&s); fileOut << print_state(&s, 27); auto instructions = generate_obvious_instructions(Text); fileOut << print_instructions(instructions); /* interpret(&s, instructions); cout << s.Out << '\n'; cout << "Instructions count: " << instructions.size() << ", cost: " << s.AccumCost << '\n'; string stateText = R"( 3 hel o i )"; string instructionsText = R"( 11 w 2 w 1 cr w 1 cd 2 w 1 cd 1 push cd 3 pop w 2 )"; initialize_state(&s, stateText); instructions = read_instructions(instructionsText); interpret(&s, instructions); cout << s.Out << '\n'; cout << "Instructions count: " << instructions.size() << ", cost: " << s.AccumCost << '\n'; */ } return 0; }