← Home
```go
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {
	// Configure scanner for fast I/O
	scanner := bufio.NewScanner(os.Stdin)
	const maxCapacity = 2 * 1024 * 1024 // 2MB buffer for large input
	buf := make([]byte, maxCapacity)
	scanner.Buffer(buf, maxCapacity)
	scanner.Split(bufio.ScanWords)

	if !scanner.Scan() {
		return
	}
	n, _ := strconv.Atoi(scanner.Text())

	if !scanner.Scan() {
		return
	}
	s := scanner.Text()

	// Rolling Hash Constants
	const mod1 int64 = 1000000007
	const mod2 int64 = 1000000009
	const base1 int64 = 31
	const base2 int64 = 37

	// Precompute powers and hashes
	pow1 := make([]int64, n+1)
	pow2 := make([]int64, n+1)
	h1 := make([]int64, n+1)
	h2 := make([]int64, n+1)

	pow1[0] = 1
	pow2[0] = 1
	for i := 1; i <= n; i++ {
		pow1[i] = (pow1[i-1] * base1) % mod1
		pow2[i] = (pow2[i-1] * base2) % mod2
	}

	for i := 0; i < n; i++ {
		c := int64(s[i] - 'a' + 1)
		h1[i+1] = (h1[i]*base1 + c) % mod1
		h2[i+1] = (h2[i]*base2 + c) % mod2
	}

	// Function to get hash of substring s[l-1...r-1] (1-based l, r)
	getHash := func(l, r int) (int64, int64) {
		lenS := r - l + 1
		v1 := (h1[r] - h1[l-1]*pow1[lenS]) % mod1
		if v1 < 0 {
			v1 += mod1
		}
		v2 := (h2[r] - h2[l-1]*pow2[lenS]) % mod2
		if v2 < 0 {
			v2 += mod2
		}
		return v1, v2
	}

	numSubs := (n + 1) / 2
	ans := make([]int, numSubs+1)

	// Iterate from the innermost substring outwards
	// We use the fact that if T_k has an odd border of length L,
	// then T_{k+1} has an odd border of length L-2.
	// Conversely, ans[k] <= ans[k+1] + 2.
	for k := numSubs; k >= 1; k-- {
		lenT := n + 2 - 2*k
		var cand int

		if k == numSubs {
			// Innermost substring
			// Max possible odd length must be < lenT
			if lenT%2 == 0 {
				cand = lenT - 1
			} else {
				cand = lenT - 2
			}
		} else {
			// Use result from previous (inner) substring to limit search
			if ans[k+1] != -1 {
				cand = ans[k+1] + 2
			} else {
				cand = 1
			}
			// Must be proper suprefix, i.e., length < lenT
			if cand >= lenT {
				cand -= 2
			}
		}

		res := -1
		// Check candidates in decreasing order. First match is maximal.
		for cand > 0 {
			// Check if T_k has border of length cand
			// Prefix of T_k starts at index k in s, length cand
			// Suffix of T_k ends at index n-k+1 in s, length cand
			
			pL, pR := k, k+cand-1
			sL, sR := n-k-cand+2, n-k+1
			
			hv1_p, hv2_p := getHash(pL, pR)
			hv1_s, hv2_s := getHash(sL, sR)
			
			if hv1_p == hv1_s && hv2_p == hv2_s {
				res = cand
				break
			}
			cand -= 2
		}
		ans[k] = res
	}

	// Output results
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()
	for i := 1; i <= numSubs; i++ {
		if i > 1 {
			out.WriteByte(' ')
		}
		fmt.Fprint(out, ans[i])
	}
	out.WriteByte('\n')
}
```