← Home
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <unordered_set>
#include <iostream>
#include <random>
#include <queue>
#include <ctime>
#include <cassert>
#include <cassert>
#include <numeric>
#include <complex>
#include <string>
#include <cstring>
#include <chrono>
#include <random>
#include <bitset>
#include <stack>
#include <fstream>
#include <array>
#include <iomanip>
#include <functional>
#include <memory>
#include <ctime>
using namespace std;
//using int = long long;
using ld = long double;
#define debug(x) std::cerr << __FUNCTION__ << ":" << __LINE__ << " " << #x << " = " << x << '\n';
const int INF = 1e9;
vector<int> z_func(string &s){
    vector<int> z(s.size());
    int l = -1;
    int r = -1;
    for (int i = 1; i < s.size(); i++){
        if (i <= r){
            z[i] = min(r - i + 1, z[i - l]);
        }
        while (i + z[i] < s.size() && s[z[i]] == s[i + z[i]]){
            z[i]++;
        }
        if (i + z[i] - 1 > r){
            r = i + z[i] - 1;
            l = i;
        }
    }
    return z;
}
struct segtree{
    int size;
    vector<int> tree;
    void init(int n){
        size = 1;
        while (size <= n) {
            size *= 2;
        }
        tree.resize(2 * size - 1, -INF);
    }
    void build(vector<int> &ar, int x, int lx, int rx){
        if (rx - lx == 1){
            if (lx < ar.size()){
                tree[x] = ar[lx];
            }
            return;
        }
        build(ar,2*x+1,lx,(lx+rx)/2);
        build(ar,2*x+2,(lx+rx)/2,rx);
        tree[x]=max(tree[2*x+1],tree[2*x+2]);
    }
    void build(vector<int> &ar){
        init(ar.size());
        build(ar,0,0,size);
    }
    int get(int l, int r, int x, int lx, int rx){
        if (r <= lx || rx <= l){
            return -INF;
        }
        if (lx >= l && rx <= r){
            return tree[x];
        }
        return max(get(l,r,2*x+1,lx,(lx+rx)/2),get(l,r,2*x+2,(lx+rx)/2,rx));
    }
    int get(int l, int r){
        r++;
        return get(l,r ,0,0,size);
    }
 
};
void solve(){
    string s;
    cin >> s;
    string s_rev = s;
    reverse(s_rev.begin(), s_rev.end());
    string s2 = s_rev + "#" + s;
    vector<int> z = z_func(s2);
    vector<int> temp(s.size());
    reverse(z.begin(), z.end());
    for (int i =0; i <= s_rev.size(); i++){
        z.pop_back();
    }
    reverse(z.begin(), z.end());
    vector<int> checker;
    int n = s.size();
    vector<int> fst(n + 1, -1);
    for (int i = 1; i <= n; i++){
        checker.push_back(i);
    }
    reverse(checker.begin(), checker.end());
    for (int i = 0; i < z.size(); i++){
        while (checker.size() && z[i] >= checker.back()){
            fst[checker.back()] = i;
            checker.pop_back();
        }
    }
    vector<int> d1(s.size());
    int l = -1;
    int r = -1;
    for (int i =0; i < s.size(); i++){
        if(i <= r){
            d1[i] = min(r - i + 1, d1[(l + r) / 2 - (i - (l + r) / 2)]);
        }
        while (i + d1[i] < n && i - d1[i] >= 0 && s[i + d1[i]] == s[i - d1[i]]){
            d1[i]++;
        }
        if (i + d1[i] -1  > r){
            r = i + d1[i] - 1;
            l = i - d1[i] + 1;
        }
    }
    fst[0]=0;
    segtree tree_odd;
    tree_odd.build(d1);
    int ans  = 0;
    int k;
    int tk = 0;
    for (int i =0; 2 * i < n; i++){
        if (fst[i]==-1){
            break;
        }
        int len_ost = n - 1 - fst[i] + 1;
        len_ost = len_ost - 2 * i;
        if (len_ost <= 0){
            continue;
        }
        int left = fst[i] + i;
        int right = n - 1 - i;
        int largest_even =0 ;
        int largest_odd = 0;
        l = 0;
        r = right - left + 1;
        int m;
        l = 0;
        r = ((right -left + 1) + 1) / 2;
        while (l < r){
            m = (l + r + 1) / 2;
            int dd = 2 * m - 1;
            if (2 * tree_odd.get(left + dd / 2, right - dd / 2) - 1 >= dd){
                l = m;
            }
            else{
                r = m - 1;
            }
        }
        largest_odd = 2*l-1;
        if (2 * i + max(largest_odd, largest_even) > ans){
            ans = 2 * i + max(largest_odd, largest_even);
            tk = i;
        }
    }
    if (tk == 0){
        cout << 1 << '\n';
        for (int i = 0; i < n; i++){
            if (2 * d1[i] - 1 == ans){
                cout << (i - d1[i] + 1) + 1 << " " << ans << '\n';
                return;
            }
        }
    }
    cout << 3 << '\n';
    int need_p = ans - 2 * tk;
    cout << fst[tk] + 1 << " " << tk << '\n';
    for (int i = 0; i < n; i++){
        if (2 * d1[i] - 1 >= need_p && (i - need_p / 2) > fst[tk] + tk - 1){
            cout << (i - need_p / 2) + 1 << " " << need_p << '\n';
            break;
        }
    }
    cout << n - tk + 1 << " " << tk << '\n';
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    t=1;
    //cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}