#include #include #include #include #include #include #include #include using namespace std; int T, N; vector words; int C; list crossword; struct word { int x, y; string dirs; }; vector moves; int minL, maxL; struct match { int c, i, j, oi, oj; }; list matches; void read() { ifstream fin("crossword.in"); fin >> T >> N; fin.ignore(); words.resize(N); moves.resize(N); for (int i = 0; i < N; i++) { getline(fin, words[i]); //cout << words[i] << endl; } } void write() { ofstream fout("crossword.out"); fout << C << " " << crossword.size() << endl; for (const string& r : crossword) fout << r << endl; for (const word& w : moves) fout << w.x << ' ' << w.y << ' ' << w.dirs << endl; } void solve1_horizontally() { C = max_element(words.begin(), words.end(), [](const string& l, const string& r) -> bool { return l.size() < r.size(); })->size(); crossword.clear(); for (int i = 0; i < N; i++) { string line(words[i]); line.resize(C, '#'); crossword.push_back(line); word& w = moves[i]; w.x = 0; w.y = i; w.dirs.clear(); w.dirs.resize(words[i].size() - 1, 'R'); } } bool solve_word(int w) { const auto& word = words[w]; auto& mvs = moves[w]; mvs.y = 0; list::iterator row; if (crossword.empty()) { crossword.push_back(string()); row = crossword.begin(); } else { row = crossword.begin(); // position on middle row while (2 * ++mvs.y < (int)crossword.size()) row++; mvs.y--; } size_t pos = row->size(); mvs.x = pos; mvs.dirs.clear(); row->push_back(word[0]); for (int i = 1, c = word.size(); i < c; i++) { char ch = word[i]; // move back if palindrome if (pos > 0 && row->at(pos - 1) == ch) { mvs.dirs.push_back('L'); pos--; continue; } // move next if at end if (pos + 1 == row->size()) { row->push_back(ch); mvs.dirs.push_back('R'); pos++; continue; } // move next if char matches if (row->at(pos + 1) == ch) { mvs.dirs.push_back('R'); pos++; continue; } // try to move to upper row auto prev = row; if (row != crossword.begin() && (--prev)->size() < pos) { row = prev; mvs.dirs.push_back('U'); row->resize(pos, '#'); row->push_back(ch); continue; } // try to move to lower row auto next = row; if (++next != crossword.end() && next->size() < pos) { row = next; mvs.dirs.push_back('D'); row->resize(pos, '#'); row->push_back(ch); continue; } // try to insert row if (row == crossword.begin()) { mvs.dirs.push_back('U'); crossword.push_front(string(pos, '#')); (--row)->push_back(ch); // start row goes down for (int j = 0; j <= w; j++) moves[j].y++; continue; } // try to append row if (next == crossword.end()) { mvs.dirs.push_back('D'); crossword.push_back(string(pos, '#')); (++row)->push_back(ch); continue; } // failed to insert next char return false; } return true; } void addMatch(const match& m) { if (m.c > 0) { auto p = matches.begin(); while (p != matches.end() && p->c > m.c) p++; matches.insert(p, m); } } void findMatches(int i, int j) { const string& wi = words[i]; const string& wj = words[j]; int k = wi.size(), l = wj.size(); if (k < l) { // if 1st word is smaller do it inverse findMatches(j, i); } else { int matchS = 0, matchE = 0; bool moreS = true, moreE = true; int oi = -1, oj = -1; for (int m = 0, c = l; (moreS || moreE) && m < c; m++) { if (moreS && wi[m] == wj[m]) matchS++; else moreS = false; if (moreE && wi[--k] == wj[--l]) { matchE++; oi = k; oj = l; } else moreE = false; } addMatch({ matchS, i, j, 0, 0 }); addMatch({ matchE, i, j, oi, oj }); } } void findMatches() { vector sorted(N); for (int i = 0; i < N; i++) sorted[i] = i; sort(sorted.begin(), sorted.end(), [](int l, int r) -> bool { return words[l] < words[r]; }); maxL = 0; for (int i = 0; i < N - 1; i++) { for (int j = i + 1; j < N; j++) { findMatches(sorted[i], sorted[j]); } } } void orderWords() { crossword.clear(); vector not_used(N, true); for (const match& m : matches) { if (not_used[m.i] && not_used[m.j]) { not_used[m.i] = false; not_used[m.j] = false; const string& wi = words[m.i]; const string& wj = words[m.j]; moves[m.i].x = 0; moves[m.i].y = crossword.size(); moves[m.i].dirs = string(wi.size() - 1, 'R'); if (m.oi == 0) { // match at start moves[m.j].x = 0; moves[m.j].y = crossword.size(); crossword.push_back(wi); string pathj(m.c - 1, 'R'); if (m.c < wj.size()) { pathj.push_back('D'); pathj.resize(wj.size() - 1, 'R'); string linej(m.c - 1, '#'); linej += wj.substr(m.c); crossword.push_back(linej); } moves[m.j].dirs = pathj; } else { // match at end crossword.push_back(wi); if (m.oj > 0) { moves[m.j].x = m.oi - m.oj + 1; moves[m.j].y = crossword.size(); string linej(m.oi - m.oj + 1, '#'); linej += wj.substr(0, m.oj); crossword.push_back(linej); string pathj(m.oj - 1, 'R'); pathj.push_back('U'); pathj.append(m.c - 1, 'R'); moves[m.j].dirs = pathj; } else { moves[m.j].x = m.oi; moves[m.j].y = moves[m.i].y; moves[m.j].dirs = string(wj.size() - 1, 'R'); } } } } for (int i = 0; i < N; i++) { if (not_used[i]) { const string& wi = words[i]; moves[i].x = 0; moves[i].y = crossword.size(); moves[i].dirs = string(wi.size() - 1, 'R'); crossword.push_back(wi); } } } void fillCrossword() { C = max_element(crossword.begin(), crossword.end(), [](const string& l, const string& r) -> bool { return l.size() < r.size(); })->size(); for (auto& l : crossword) { l.resize(C, '#'); } } void solve1() { findMatches(); //minL = words[sorted[0]].size(); //maxL = words[sorted[N - 1]].size(); orderWords(); } void solve3() { vector sorted(N); for (int i = 0; i < N; i++) sorted[i] = i; sort(sorted.begin(), sorted.end(), [](int l, int r) -> bool { return words[l].size() < words[r].size(); }); list sortedL(sorted.begin(), sorted.end()); crossword.clear(); while (!sortedL.empty()) { int hwi = sortedL.back(); const string& hw = words[hwi]; int hws = hw.size(); sortedL.pop_back(); vector vwis(hws, -1), vwpos(hws); int vpos = 0, vsize = 1, vabspos = crossword.size(); crossword.push_back(hw); auto vstart = crossword.end(); vstart--; for (int i = 0; i < hws; i++) { for (int vwi : sortedL) { const string& vw = words[vwi]; auto pos = vw.find(hw[i]); if (pos != string::npos) { vwis[i] = vwi; vwpos[i] = pos; sortedL.remove(vwi); while (vpos < pos) { vpos++; vsize++; vstart = crossword.insert(vstart, string(hw.size(), '#')); } auto vptr = vstart; while (vpos > pos) vptr++, pos++; for (int j = 0, jc = vw.size(); j < jc; j++) { if (vptr == crossword.end()) { vptr = crossword.insert(vptr, string(hw.size(), '#')); vsize++; } (*vptr++)[i] = vw[j]; } break; } } } moves[hwi].x = 0; moves[hwi].y = vabspos + vpos; moves[hwi].dirs = string(hw.size() - 1, 'R'); for (int i = 0; i < hws; i++) { int vwi = vwis[i]; if (vwi >= 0) { moves[vwi].x = i; moves[vwi].y = vabspos + vpos - vwpos[i]; moves[vwi].dirs = string(words[vwi].size() - 1, 'D'); } } } } int main() { read(); switch (T) { case 1: case 4: solve1(); break; case 2: if (N > 1 || !solve_word(0)) solve1_horizontally(); break; case 3: case 5: default: solve3(); break; //default: // solve1(); //bool failed = false; //for (int i = 0; i < N; i++) //{ // if (!solve_word(i)) // { // failed = true; // break; // } //} //if (failed) // solve1_horizontally(); //break; } fillCrossword(); write(); return 0;// N * 1000000 + T;// *1000 + minL; }