← Home
package main

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

func buildSA(s []int) []int {
	n := len(s)
	p := make([]int, n)
	c := make([]int, n)
	cntSize := n
	if cntSize < 28 {
		cntSize = 28
	}
	cnt := make([]int, cntSize)
	for i := 0; i < n; i++ {
		cnt[s[i]]++
	}
	for i := 1; i < cntSize; i++ {
		cnt[i] += cnt[i-1]
	}
	for i := 0; i < n; i++ {
		x := s[i]
		cnt[x]--
		p[cnt[x]] = i
	}
	classes := 1
	c[p[0]] = 0
	for i := 1; i < n; i++ {
		if s[p[i]] != s[p[i-1]] {
			classes++
		}
		c[p[i]] = classes - 1
	}
	pn := make([]int, n)
	cn := make([]int, n)
	for h := 0; (1 << h) < n; h++ {
		shift := 1 << h
		for i := 0; i < n; i++ {
			pn[i] = p[i] - shift
			if pn[i] < 0 {
				pn[i] += n
			}
		}
		for i := 0; i < classes; i++ {
			cnt[i] = 0
		}
		for i := 0; i < n; i++ {
			cnt[c[pn[i]]]++
		}
		for i := 1; i < classes; i++ {
			cnt[i] += cnt[i-1]
		}
		for i := n - 1; i >= 0; i-- {
			x := pn[i]
			cl := c[x]
			cnt[cl]--
			p[cnt[cl]] = x
		}
		classes = 1
		cn[p[0]] = 0
		for i := 1; i < n; i++ {
			cur := p[i]
			prev := p[i-1]
			cur2 := cur + shift
			if cur2 >= n {
				cur2 -= n
			}
			prev2 := prev + shift
			if prev2 >= n {
				prev2 -= n
			}
			if c[cur] != c[prev] || c[cur2] != c[prev2] {
				classes++
			}
			cn[cur] = classes - 1
		}
		copy(c, cn)
	}
	return p
}

func buildLCP(s []int, sa []int) []int {
	n := len(s)
	rank := make([]int, n)
	for i, p := range sa {
		rank[p] = i
	}
	lcp := make([]int, n-1)
	k := 0
	for i := 0; i < n; i++ {
		r := rank[i]
		if r == n-1 {
			k = 0
			continue
		}
		j := sa[r+1]
		for i+k < n && j+k < n && s[i+k] == s[j+k] {
			k++
		}
		lcp[r] = k
		if k > 0 {
			k--
		}
	}
	return lcp
}

func manacherOdd(s string) []int {
	n := len(s)
	d1 := make([]int, n)
	l, r := 0, -1
	for i := 0; i < n; i++ {
		k := 1
		if i <= r {
			mirror := l + r - i
			if d1[mirror] < r-i+1 {
				k = d1[mirror]
			} else {
				k = r - i + 1
			}
		}
		for i-k >= 0 && i+k < n && s[i-k] == s[i+k] {
			k++
		}
		d1[i] = k
		if i+k-1 > r {
			l = i - k + 1
			r = i + k - 1
		}
	}
	return d1
}

func main() {
	in := bufio.NewReaderSize(os.Stdin, 1<<20)
	var s string
	fmt.Fscan(in, &s)
	n := len(s)

	rev := make([]byte, n)
	for i := 0; i < n; i++ {
		rev[i] = s[n-1-i]
	}

	arr := make([]int, 0, 2*n+2)
	for i := 0; i < n; i++ {
		arr = append(arr, int(s[i]-'a')+1)
	}
	arr = append(arr, 27)
	for i := 0; i < n; i++ {
		arr = append(arr, int(rev[i]-'a')+1)
	}
	arr = append(arr, 0)

	sa := buildSA(arr)
	lcp := buildLCP(arr, sa)

	d1 := manacherOdd(s)

	lg := make([]int, n+1)
	for i := 2; i <= n; i++ {
		lg[i] = lg[i/2] + 1
	}
	K := lg[n] + 1
	st := make([][]int, K)
	st[0] = make([]int, n)
	copy(st[0], d1)
	for k := 1; k < K; k++ {
		span := 1 << k
		half := span >> 1
		m := n - span + 1
		row := make([]int, m)
		prev := st[k-1]
		for i := 0; i < m; i++ {
			if prev[i] > prev[i+half] {
				row[i] = prev[i]
			} else {
				row[i] = prev[i+half]
			}
		}
		st[k] = row
	}

	rangeMax := func(l, r int) int {
		if l > r {
			return 0
		}
		k := lg[r-l+1]
		a := st[k][l]
		b := st[k][r-(1<<k)+1]
		if a > b {
			return a
		}
		return b
	}

	size := 1
	for size < n {
		size <<= 1
	}
	seg := make([]int, size<<1)
	for i := 0; i < n; i++ {
		seg[size+i] = d1[i]
	}
	for i := size - 1; i >= 1; i-- {
		if seg[i<<1] > seg[i<<1|1] {
			seg[i] = seg[i<<1]
		} else {
			seg[i] = seg[i<<1|1]
		}
	}

	var findFirst func(node, nl, nr, l, r, thr int) int
	findFirst = func(node, nl, nr, l, r, thr int) int {
		if l > nr || r < nl || seg[node] <= thr {
			return -1
		}
		if nl == nr {
			return nl
		}
		mid := (nl + nr) >> 1
		res := findFirst(node<<1, nl, mid, l, r, thr)
		if res != -1 {
			return res
		}
		return findFirst(node<<1|1, mid+1, nr, l, r, thr)
	}

	bestPal := func(L, R int) (int, int) {
		lo, hi := 0, (R-L)/2
		for lo < hi {
			mid := (lo + hi + 1) >> 1
			if rangeMax(L-1+mid, R-1-mid) > mid {
				lo = mid
			} else {
				hi = mid - 1
			}
		}
		t := lo
		c := findFirst(1, 0, size-1, L-1+t, R-1-t, t)
		return 2*t + 1, c + 1 - t
	}

	const INF = int(1e9)

	m := len(sa)
	capNodes := 2*m + 5
	depth := make([]int, 0, capNodes)
	parent := make([]int, 0, capNodes)
	leafPos := make([]int, 0, capNodes)
	first := make([]int, 0, capNodes)
	last := make([]int, 0, capNodes)
	prevSib := make([]int, 0, capNodes)
	nextSib := make([]int, 0, capNodes)
	minS := make([]int, 0, capNodes)
	minT := make([]int, 0, capNodes)

	newNode := func(dep, pos int) int {
		id := len(depth)
		depth = append(depth, dep)
		parent = append(parent, -1)
		leafPos = append(leafPos, pos)
		first = append(first, -1)
		last = append(last, -1)
		prevSib = append(prevSib, -1)
		nextSib = append(nextSib, -1)
		minS = append(minS, INF)
		minT = append(minT, INF)
		return id
	}

	appendChild := func(p, ch int) {
		parent[ch] = p
		prevSib[ch] = last[p]
		nextSib[ch] = -1
		if last[p] != -1 {
			nextSib[last[p]] = ch
		} else {
			first[p] = ch
		}
		last[p] = ch
	}

	detachLast := func(p int) int {
		ch := last[p]
		pr := prevSib[ch]
		if pr != -1 {
			nextSib[pr] = -1
		} else {
			first[p] = -1
		}
		last[p] = pr
		parent[ch] = -1
		prevSib[ch] = -1
		nextSib[ch] = -1
		return ch
	}

	root := newNode(0, -1)
	stack := []int{root}
	for i, pos := range sa {
		l := 0
		if i > 0 {
			l = lcp[i-1]
		}
		for depth[stack[len(stack)-1]] > l {
			stack = stack[:len(stack)-1]
		}
		if depth[stack[len(stack)-1]] < l {
			p := stack[len(stack)-1]
			v := newNode(l, -1)
			ch := detachLast(p)
			appendChild(p, v)
			appendChild(v, ch)
			stack = append(stack, v)
		}
		leaf := newNode(0, pos)
		appendChild(stack[len(stack)-1], leaf)
	}

	order := make([]int, 0, len(depth))
	stk := []int{root}
	for len(stk) > 0 {
		v := stk[len(stk)-1]
		stk = stk[:len(stk)-1]
		order = append(order, v)
		for ch := first[v]; ch != -1; ch = nextSib[ch] {
			stk = append(stk, ch)
		}
	}
	for i := len(order) - 1; i >= 0; i-- {
		v := order[i]
		if first[v] == -1 {
			pos := leafPos[v]
			if pos >= 0 && pos < n {
				minS[v] = pos + 1
			} else if pos > n && pos < 2*n+1 {
				minT[v] = pos - n
			}
		} else {
			ms, mt := INF, INF
			for ch := first[v]; ch != -1; ch = nextSib[ch] {
				if minS[ch] < ms {
					ms = minS[ch]
				}
				if minT[ch] < mt {
					mt = minT[ch]
				}
			}
			minS[v] = ms
			minT[v] = mt
		}
	}

	bestTotal, bestMidStart := bestPal(1, n)
	bestMidLen := bestTotal
	bestK := 1
	bestPrefixStart := 0
	bestOuterLen := 0
	bestSuffixStart := 0

	for v := 1; v < len(depth); v++ {
		if first[v] == -1 || depth[v] == 0 || minS[v] == INF || minT[v] == INF {
			continue
		}
		A := minS[v]
		C := n - minT[v] + 1
		limit := (C - A) / 2
		d := depth[v]
		if limit < d {
			d = limit
		}
		pd := 0
		if parent[v] != -1 {
			pd = depth[parent[v]]
		}
		if d <= pd || d <= 0 {
			continue
		}
		L := A + d
		R := C - d
		palLen, palStart := bestPal(L, R)
		total := 2*d + palLen
		if total > bestTotal {
			bestTotal = total
			bestK = 3
			bestPrefixStart = A
			bestOuterLen = d
			bestMidStart = palStart
			bestMidLen = palLen
			bestSuffixStart = R + 1
		}
	}

	out := bufio.NewWriterSize(os.Stdout, 1<<20)
	defer out.Flush()

	fmt.Fprintln(out, bestK)
	if bestK == 1 {
		fmt.Fprintln(out, bestMidStart, bestMidLen)
	} else {
		fmt.Fprintln(out, bestPrefixStart, bestOuterLen)
		fmt.Fprintln(out, bestMidStart, bestMidLen)
		fmt.Fprintln(out, bestSuffixStart, bestOuterLen)
	}
}