## 1) Abridged problem statement

You are given 1…1000 lines of "wiki text".
A line may start with `*` (unordered list marker) or `#` (ordered list marker), or with any other character (plain text).

Rules:

- **A list** is formed by a **maximal group of ≥ 2 consecutive lines** that start with the **same marker** (`*` or `#`).
  It becomes `<ul> ... </ul>` for `*` or `<ol> ... </ol>` for `#`.
- Inside a list, each element is wrapped as:
  ```
  <li>
  CONTENT
  </li>
  ```
- **Nested lists:** inside a list, if there is a **group of ≥ 2 consecutive elements** whose contents start with the same marker (`*` or `#`), then those elements become a nested list. This is applied **recursively**.
- Output the corresponding HTML, with **every tag and every text line on its own line**, and **no extra spaces**.

---

## 2) Detailed editorial (explaining the given solution)

### Key observation

This is a parsing problem governed by a single repeated rule:

> Whenever you have **two or more consecutive lines** starting with the same marker (`*` or `#`), you must convert them into an HTML list of that type, and then recursively apply the same rule on their contents **after removing one leading marker**.

This recursion naturally handles unlimited nesting depth.

### How the provided solution structures it

1. **Read all input lines** into a global `vector<string> lines`.
2. Run a recursive function:
   ```cpp
   process(items, wrap_in_li)
   ```
   where:
   - `items` are the "current level" lines being processed
   - `wrap_in_li` indicates whether each produced "item" at this level must be surrounded by `<li>...</li>`
     (At the top level it's `false`, because top-level plain lines should be printed as-is.)

### What `process()` does

It scans `items` left-to-right using index `i`.

For each position `i`:

1. Let `c = items[i][0]`.
2. If `c` is `*` or `#`, it tries to extend a maximal block `[i, j)` such that every `items[k]` in the block starts with the same marker `c`.
3. If the block length `(j - i) >= 2`, then by the rules this block is a list:
   - If `wrap_in_li` is true, print `<li>` (because this entire list is itself the content of a parent list element).
   - Print `<ul>` or `<ol>` depending on `c`.
   - Create a new array `stripped` by removing the first character from each line in the block (`substr(1)`).
   - Recursively call `process(stripped, true)` because inside an HTML list, each element must be wrapped in `<li>`.
   - Close `</ul>` / `</ol>`.
   - If needed, close the outer `<li>`.
   - Set `i = j` and continue scanning.

4. Otherwise (not a list block, i.e., marker doesn't form a group of ≥2, or line doesn't start with marker):
   - If `wrap_in_li` is true, wrap this single line in `<li> ... </li>`.
   - Otherwise just print the line as plain text.
   - Increment `i`.

### Why this matches the statement exactly

- "Group of ≥2 consecutive lines with same marker becomes a list": handled by the `(j-i>=2)` check.
- "Nested lists determined the same way, recursively": achieved by stripping one marker and calling `process()` again on the stripped lines.
- "A single marked line is not a list": if block size is 1, it is printed literally (possibly inside `<li>`).
- "Tags on separate lines": every output piece is printed with `\n` accordingly.

### Complexity

Let `L` be total input length (≤ 1000 characters).
Each recursion strips one character from lines involved; total work is linear in the total size of all intermediate strings, which remains small under constraints. Easily fits.

---

## 3) C++ Solution

```cpp
#include <bits/stdc++.h>

using namespace std;

template<typename T1, typename T2>
ostream& operator<<(ostream& out, const pair<T1, T2>& x) {
    return out << x.first << ' ' << x.second;
}

template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& x) {
    return in >> x.first >> x.second;
}

template<typename T>
istream& operator>>(istream& in, vector<T>& a) {
    for(auto& x: a) {
        in >> x;
    }
    return in;
};

template<typename T>
ostream& operator<<(ostream& out, const vector<T>& a) {
    for(auto x: a) {
        out << x << ' ';
    }
    return out;
};

vector<string> lines;

void read() {
    string line;
    while(getline(cin, line)) {
        lines.push_back(line);
    }
}

void process(const vector<string>& items, bool wrap_in_li) {
    int n = (int)items.size();
    int i = 0;
    while(i < n) {
        char c = items[i][0];
        if(c == '#' || c == '*') {
            int j = i;
            while(j < n && !items[j].empty() && items[j][0] == c) {
                j++;
            }
            if(j - i >= 2) {
                if(wrap_in_li) {
                    cout << "<li>\n";
                }
                cout << (c == '#' ? "<ol>" : "<ul>") << "\n";
                vector<string> stripped;
                for(int k = i; k < j; k++) {
                    stripped.push_back(items[k].substr(1));
                }
                process(stripped, true);
                cout << (c == '#' ? "</ol>" : "</ul>") << "\n";
                if(wrap_in_li) {
                    cout << "</li>\n";
                }
                i = j;
                continue;
            }
        }
        if(wrap_in_li) {
            cout << "<li>\n";
        }
        cout << items[i] << "\n";
        if(wrap_in_li) {
            cout << "</li>\n";
        }
        i++;
    }
}

void solve() {
    // The algorithm here isn't complicated. It's again a parsing problem.
    process(lines, false);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int T = 1;
    // cin >> T;
    for(int test = 1; test <= T; test++) {
        read();
        solve();
    }

    return 0;
}
```

---

## 4) Python solution (same logic) with detailed comments

```python
import sys

def process(items, wrap_in_li):
    """
    items: list of strings to process at the current nesting level
    wrap_in_li:
      - False at top level: print plain lines directly
      - True inside an HTML list: every produced element must be wrapped in <li>..</li>
    """
    n = len(items)
    i = 0

    while i < n:
        c = items[i][0]

        # Attempt to form a list block if the line starts with '*' or '#'
        if c in ('*', '#'):
            j = i
            # Extend j over consecutive lines that start with the same marker
            while j < n and items[j] and items[j][0] == c:
                j += 1

            # If block size >= 2, it is a list per the statement
            if j - i >= 2:
                if wrap_in_li:
                    print("<li>")

                # Open correct list tag
                print("<ol>" if c == '#' else "<ul>")

                # Strip one marker and recurse; inside a list, elements must be <li>-wrapped
                stripped = [items[k][1:] for k in range(i, j)]
                process(stripped, True)

                # Close list tag
                print("</ol>" if c == '#' else "</ul>")

                if wrap_in_li:
                    print("</li>")

                i = j
                continue

        # Not a list block: output this single line as a plain item
        if wrap_in_li:
            print("<li>")
        print(items[i])
        if wrap_in_li:
            print("</li>")

        i += 1


def main():
    # Read all lines exactly (strip only the trailing newline)
    lines = [line.rstrip('\n') for line in sys.stdin]

    # Top level: do not wrap lines in <li>
    process(lines, False)

if __name__ == "__main__":
    main()
```

---

## 5) Compressed editorial

Read all lines. Recursively scan a list of lines left-to-right. At position `i`, if `items[i]` starts with `*` or `#`, extend `j` while consecutive lines share that same first character. If `j-i>=2`, output `<ul>`/`<ol>`, recurse on those lines with the first character removed, and inside the recursion wrap each produced element in `<li>`. If this nested list is itself within a parent list item, surround the entire `<ul>/<ol>` block with `<li>...</li>`. If no block of size ≥2 exists, output the single line literally (wrapped in `<li>` only when inside a list). This exactly implements both list formation and nesting rules.
