1. Abridged Problem Statement

There are n heaps in a line with sizes a1, a2, ..., an. Players alternate turns. On a turn, a player chooses either the current first or current last heap and removes any positive number of stones from that heap. When a heap becomes empty, it disappears and the next heap becomes the new end. The player who cannot move (all heaps are gone) loses. Fedor moves first. Determine the winner assuming optimal play (print "FEDOR" or "SERGEY"). Constraints: 1 ≤ n ≤ 5.

---

2. Detailed Editorial

Interval view and P-positions:
- For 2 heaps, this is exactly Nim on two piles: the next player loses if and only if the two piles are equal.
- For more than 2 heaps, only the two ends are accessible at any time. The middle segment [l+1..r-1] acts as a "filter/transform" between the ends l and r.

Define the middle transform g[l, r]:
- Fix the middle segment a[l+1..r-1]. For any x ≥ 1 placed at the left end, let g[l, r](x) be the unique y ≥ 1 (if it exists) such that the position (x, a[l+1..r-1], y) is a P-position (losing for the next player).
- If no such y ≥ 1 exists, record g[l, r](x) = 0 as a sentinel.
- Uniqueness: If two different y1 < y2 both yielded losing positions, each could move to the other, contradicting the definition of a P-position. So for a fixed x there can be at most one losing y.

Structure of g[l, r]:
- Surprisingly, each function g[l, r] can be encoded by just two integers (L, R).
- The induced mapping f(x) = g[l, r](x) behaves as follows:
  - If x is outside the closed interval [min(L, R), max(L, R)], then f(x) = x (identity).
  - If x lies inside that interval, f(x) moves one step toward R:
    - If L ≤ R: f(x) = x + 1 when x < R, and f(R) = 0 (no losing match).
    - If L > R: f(x) = x − 1 when x > R, and f(R) = 0.
- Intuition: Inside the "active" range, every time you increase the left end by 1 you need to increase/decrease the right end by one step in lockstep to preserve a P-position, up to the boundary where no match exists.

Base case (length 2):
- For r = l+1, the middle is empty and the game is exactly two-heap Nim. Losing happens only when the two ends are equal.
- This corresponds to the identity mapping f(x) = x. We encode that by the pair (0, 0), because the apply rule with (L, R) = (0, 0) is identity for all positive x.

Inversion:
- The inverse mapping of g[l, r] (mapping "desired right end → losing left end") is obtained by swapping the pair: inv(L, R) = (R, L).
- This follows from the symmetry of the game and the fact that the step function is reversible outside the sentinel at R.

DP recurrence for pairs:
- We build g[l, r] from smaller intervals:
  - Let L' = g[l+1, r](a[l+1]). This is the unique losing right-end value if we first clear a[l] completely. We record it as L for g[l, r].
  - Let R' = inv(g[l, r−1])(a[r−1]). This is the unique losing left-end value if we first clear a[r] completely. We record it as R for g[l, r].
  - Thus g[l, r] = (L, R).
- With the (L, R) encoding and the apply function described above, this inductive construction matches the behavior of optimal play.

Final decision:
- Compute target = g[1, n](a1) using the constructed pair for the whole interval.
- If target equals an (the actual rightmost heap), then the starting position is losing for the next player (Sergey wins), otherwise Fedor wins.
- Special case n = 1: Fedor always wins (he takes the only heap).

Complexity:
- We fill an O(n × n) table of pairs; each transition is O(1). Time and memory are O(n^2).
- This avoids any dependence on the magnitudes of the ai.

---

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;
}

int n;
vector<int> a;

static inline int apply_func(pair<int, int> fn, int x) {
    // apply_func represents the middle transform g[l,r](x) with a pair (L, R)
    // and applies it to x as described in the analysis.

    int L = fn.first, R = fn.second;
    int lo = min(L, R), hi = max(L, R);
    // If x is outside [lo, hi], return x unchanged
    if(max(lo, min(x, hi)) != x) {
        return x;
    }
    // Otherwise step toward R by +1 if L <= R else -1;
    // hitting R maps to 0
    int step;
    if(L <= R) {
        step = 1;
    } else {
        step = -1;
    }
    if(x != R) {
        return x + step;
    } else {
        return 0;
    }
}

void read() {
    cin >> n;
    a.resize(n);
    cin >> a;
}

void solve() {
    // There is a direct O((n*max)^2) solution with DP, but this is too slow
    // under the given constraints. Instead, we will make a series of
    // observations and derive a O(n^2) solution.
    //
    // - With two heaps, this is Nim on 2 piles: the player to move loses
    //   exactly when the two ends are equal (a[1] == a[2]).
    //
    // - For more heaps, the middle segment acts like a transform that maps
    //   the leftmost size x to the unique rightmost size y that makes the
    //   position losing (a P-position). Call this mapping g[l,r](x).
    //
    // - To show the uniqueness of the losing y for a given x, consider the
    //   following:
    //     (1) Any q < g[l,r](x) can be reached in a single move; if such a q
    //         were losing, then g[l,r](x) would be winning - contradiction.
    //     (2) Any q > g[l,r](x) is winning because it can move to g[l,r](x),
    //         which is losing by definition.
    //
    // - By looking of the structure of g[l,r], and an argument similar to
    //   above, we can notice that we can encode each g[l,r] by a pair (L, R):
    //     (1) If x is outside the closed interval between L and R, g(x) = x.
    //         Intuitively, we can think of this as a symmetry argument, as the
    //         "inner" range is effectively losing.
    //     (2) If x lies inside that interval, g[l,r](x) moves by one toward R;
    //         for example if moving, g[l,r](R) = 0 (meaning: there is no
    //         positive y that makes the position losing).
    //
    // - We can build up g[l,r] recursively:
    //     (1) Let g[l,r] store the pair (L, R) that encodes it.
    //     (2) For intervals of length 2, the middle is empty, so g is identity,
    //         or g = (0, 0). Expanding here, the only losing states are when
    //         the second player mirrors the first (Nim on 2 heaps).
    //     (3) For length >= 3, we can reuse the already computed g[l+1,r] and
    //         g[l,r-1] to compute g[l,r]:
    //         * g[l+1,r](a[l+1]) gives us the unique losing value for a[r]
    //           assuming a[l] has been cleared. Denote it L'.
    //         * inv(g[l,r-1])(a[r-1]) gives us the unique loosing value for
    //           a[l] assuming a[r] has been cleared. Denote it R'.
    //         * WLOG, assume L' < R'. We can notice immediately that g[l,r](x)
    //           can't be L' because we can win by fully clearing a[l]. We can
    //           also notice that g[l,r](x) = x for x < L' because if a[l] =
    //           a[r] = x, the second player can mirror the first one until the
    //           game ends. This requires some time to get convinced. Let's now
    //           consider x = L'. We can show that a[r] = L'+1 is losing for
    //           the first player, because all reachable states (reduction in
    //           a[l] or a[r]) are winning. This is one of the key observations
    //           - by similar logic, we can show that g[l,r](L'+1) = L'+2, and
    //           so on, until we reach R' where we have to think a bit more.
    //           Intuitively, we should expect g[l,r](R') = R'+1 using the
    //           same "cascading" logic, but we will show that g[l,r](R') = 0,
    //           meaning there is no y that makes the position losing. This is
    //           because we know that a[l] = R' is losing if a[r] is cleared. We
    //           are now left with a[l] > R'. In this case, if a[r] = R', the
    //           second player can either immediately force the first one into
    //           one of the above-described losing states, or if the first
    //           player goes to a[l] = R', the second player can clear a[r] and
    //           win.
    //     (4) The case L' > R' is symmetric. We can notice that g[l,r] can be
    //         "inverted" for the L',R'. This is particularly useful because
    //         it gives us the function f(x) = y meaning the loosing a[l] = y
    //         when a[r] = x. We compute R' precisely this way.
    //
    // - Final decision is simple:
    //     Fedor (first player) wins unless a[n] == g[1,n](a[1]).

    if(n == 1) {
        cout << "FEDOR\n";
        return;
    }

    // g[l][r] encodes g[l,r] as a pair (L, R)
    vector<vector<pair<int, int>>> g(n, vector<pair<int, int>>(n, {0, 0}));

    for(int len = 3; len <= n; ++len) {
        for(int l = 0; l + len <= n; ++l) {
            int r = l + len - 1;
            g[l][r] = {
                // L_{l,r} = g[l+1,r](a[l+1])
                apply_func(g[l + 1][r], a[l + 1]),
                // R_{l,r} = inv(g[l,r-1]) applied to a[r-1]
                apply_func({g[l][r - 1].second, g[l][r - 1].first}, a[r - 1])
            };
        }
    }

    int target = apply_func(g[0][n - 1], a[0]);
    if(target == a[n - 1]) {
        cout << "SERGEY\n";
    } else {
        cout << "FEDOR\n";
    }
}

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

    int T = 1;
    // cin >> T;
    for(int test = 1; test <= T; test++) {
        read();
        // cout << "Case #" << test << ": ";
        solve();
    }

    return 0;
}
```

---

4. Python Solution

```python
import sys


def apply_func(fn, x):
    """
    Apply the encoded transform g[l, r] to x.
    fn is a tuple (L, R).
    Behavior:
      - If x not in [min(L, R), max(L, R)], return x (identity).
      - Else move one step toward R; if x == R, return 0 (sentinel: no losing y).
    """
    L, R = fn
    lo, hi = (L, R) if L <= R else (R, L)
    if x < lo or x > hi:
        return x
    step = 1 if L <= R else -1
    if x != R:
        return x + step
    else:
        return 0


def solve():
    data = sys.stdin.read().strip().split()
    it = iter(data)
    n = int(next(it))
    a = [int(next(it)) for _ in range(n)]

    if n == 1:
        print("FEDOR")
        return

    g = [[(0, 0) for _ in range(n)] for __ in range(n)]

    for length in range(3, n + 1):
        for l in range(0, n - length + 1):
            r = l + length - 1
            L = apply_func(g[l + 1][r], a[l + 1])
            inv_pair = (g[l][r - 1][1], g[l][r - 1][0])
            R = apply_func(inv_pair, a[r - 1])
            g[l][r] = (L, R)

    target = apply_func(g[0][n - 1], a[0])
    print("SERGEY" if target == a[n - 1] else "FEDOR")


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

---

5. Compressed Editorial

- Reduce the game on an interval [l, r] to a mapping g[l, r] from the left end size x to the unique right end size y making (x, middle, y) a P-position, or 0 if no such y exists.
- Each g[l, r] can be encoded by a pair (L, R), meaning: outside [min(L, R), max(L, R)] the mapping is identity; inside, it steps one unit toward R; at x = R it returns 0.
- Base for length 2 is identity (two-heap Nim loses iff equal), i.e., pair (0, 0).
- Recur for longer intervals:
  - L = g[l+1, r](a[l+1]) (clear left first),
  - R = inv(g[l, r−1])(a[r−1]) (clear right first), where inv swaps (L, R).
- After filling all pairs, compute target = g[1, n](a1). If target equals an, the start is losing for the next player (print SERGEY), otherwise print FEDOR.
- Time and memory are O(n^2); no dependence on the magnitudes of ai.
