Problem:
Square Factors
In the ancient nation of Iwashiro, there was little rain this year, and the people were in trouble. That's why you, a new priest, have decided to perform a rain-making ceremony at Ryugasawa.
In the rain-making ceremony, you chant the prayer incantation written in the prayer book for the Dragon God to make it rain. When you finish the spell, the dragon god will ask you how many times the same word appears twice in a row in the spell. If you guess it, your prayer will be fulfilled and the Dragon God will send rain to you.
For example, if you cast the incantation
ababababab
, the six places in the incantation where the same word appears twice in a row are as follows.
One place for
abababab
, starting with the first letter (
abab
appears twice in a row).
Three places for
abab
, starting with the first, third, and fifth letters, respectively (
ab
appears twice in a row).
Two
baba
places (
ba
appears twice in a row) starting with the second and fourth letters, respectively.
In order for your prayers to be fulfilled, you must answer the exact number of such passages when you cast any spell.
Given a string, create a program to find the number of places in the string where the same string appears twice in a row.
Input
The input is given in the following format.
$str$
A string $str$ consisting of English and lowercase letters is given on one line. However, the length of $str$ must be between 3 and 100,000.
Output
Output the number of times the same string appears twice in a given string on a single line.
Sample Input and Output
Sample Input 1
abababab
Sample Output 1
6
Sample Input 2
aaaaaaa
Sample Output 2
12

Submitted solutions:

code_snippet: #pragma GCC target("avx2")
#include <bits/stdc++.h>
using namespace std;
#define int long long
int N;
int A[100100], I2[100100], I2_[100100];
int R1[100100], R2[100100];
int bs = 27;
int mod2 = 998244853;
int pw(int a, int p, int mod){
    int ans = 1, now = a;
    while(p){
        if(p&1) ans *= now;
        ans %= mod;
        now *= now;
        now %= mod;
        p >>= 1;
    }
    return ans;
}
int v(int a, int mod){
    return pw(a,mod-2,mod);
}
int hs(int l, int r){ // [l,r)
    int b = R2[r]-R2[l];
    b *= I2_[l];
    b %= mod2;
    b = (b+mod2)%mod2;
    return b;
}
signed main(){
    string S;
    cin>>S;
    N = S.size();
    for(int i=0;i<N;i++) A[i] = S[i]-'a'+1;
    I2[0] = 1;
    for(int i=0;i<N;i++){
        I2[i+1] = I2[i]*bs%mod2;
        I2_[i] = v(I2[i],mod2);
        R2[i+1] = (R2[i]+A[i]*I2[i])%mod2;
    }
    int ans = 0;
    auto f = [&](auto &&self, int a, int b) -> void {
        int l = a, r = b;
        if(a+1 == b){
            return;
        }
        if(a+2 == b){
            ans += (A[a] == A[a+1]);
            return;
        }
        if(a+3 == b){
            if(A[a] == A[a+1]) ans++;
            if(A[a+1] == A[a+2]) ans++;
            return;
        }
        int md = (a+b)/2;
        self(self,a,md);
        self(self,md,b);
        for(int i=1;i<=N;i++){
            if(md-i < a || b < md+i) break;
            ans += (hs(md-i,md) == hs(md,md+i));
        }
        for(int i=md+2;i<r;i++)if(A[i] == A[md] && A[md-1] == A[i-1]){
            int ac = md+1, wa = i;
            while(wa-ac > 1){
                int m = (ac+wa)/2;
                int d = m-md;
                if(i+d > r || md+d > r){
                    wa = m;
                    continue;
                }
                if(hs(md,md+d) == hs(i,i+d)) ac = m;
                else wa = m;
            }
            int l1 = md, r1 = ac;
            ac = i-1, wa = md;
            while(ac-wa > 1){
                int m = (ac+wa)/2;
                int d = i-m;
                if(md-d < l || i-d < l){
                    wa = m;
                    continue;
                }
                if(hs(md-d,md) == hs(i-d,i)) ac = m;
                else wa = m;
            }
            int l2 = ac, r2 = i;
            ans += max(0ll,r1-l2+1);
        }
        for(int i=l+1;i<md-1;i++)if(A[i] == A[md] && A[md-1] == A[i-1]){
            int wa = md, ac = i+1;
            while(wa-ac > 1){
                int m = (ac+wa)/2;
                int d = m-i;
                if(md+d > r || i+d > r){
                    wa = m;
                    continue;
                }
                if(hs(md,md+d) == hs(i,i+d)) ac = m;
                else wa = m;
            }
            int l1 = i, r1 = ac;
            ac = md-1, wa = i;
            while(ac-wa > 1){
                int m = (ac+wa)/2;
                int d = md-m;
                if(i-d < l || md-d < l){
                    wa = m;
                    continue;
                }
                if(hs(md-d,md) == hs(i-d,i)) ac = m;
                else wa = m;
            }
            int l2 = ac, r2 = md;
            //cout<<a<<' '<<b<<' '<<i<<' '<<l1<<' '<<r1<<' '<<l2<<' '<<r2<<endl;
            ans += max(0ll,r1-l2+1);
        }
        return;
    };
    f(f,0,N);
    cout<<ans<<endl;
}
accuracy: 1
time_ms: 530
memory_kb: 6612
final_rank: 8

code_snippet: // AOJ #477 Square Factors
// 2025.3.29

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct State {
    int len, link;
    int next[26];
    vector<int> occ;
    State() : len(0), link(-1) {
        memset(next, -1, sizeof(next));
    }
};

struct SuffixAutomaton {
    vector<State> st;
    int last;
    SuffixAutomaton(int n) {
        st.resize(2*n);
        st[0].len = 0;
        st[0].link = -1;
        last = 0;
        size = 1;
    }
    int size;

    void extend(char c, int pos) {
        int cur = size++;
        st[cur].len = st[last].len + 1;
        st[cur].occ.push_back(pos);
        int p = last;
        int ci = c - 'a';
        for(; p != -1 && st[p].next[ci] == -1; p = st[p].link) st[p].next[ci] = cur;
        if(p == -1) st[cur].link = 0;
        else {
            int q = st[p].next[ci];
            if(st[p].len + 1 == st[q].len) st[cur].link = q;
            else {
                int clone = size++;
                st[clone].len = st[p].len + 1;
                memcpy(st[clone].next, st[q].next, sizeof(st[q].next));
                st[clone].link = st[q].link;
                for(; p != -1 && st[p].next[ci] == q; p = st[p].link) st[p].next[ci] = clone;
                st[q].link = st[cur].link = clone;
            }
        }
        last = cur;
    }

    void merge_occurrences() {
        int sz = size;
        vector<int> deg(sz,0);
        for (int i = 1; i < sz; i++) deg[ st[i].link ]++;

        queue<int> que;
        for (int i = 0; i < sz; i++) if(deg[i]==0) que.push(i);

        while(!que.empty()){
            int v = que.front();
            que.pop();
            if(st[v].link != -1){
                int p = st[v].link;
                vector<int>& a = st[p].occ;
                vector<int>& b = st[v].occ;
                vector<int> merged;
                merged.resize(a.size() + b.size());
                merge(a.begin(), a.end(), b.begin(), b.end(), merged.begin());
                a.swap(merged);
                if(--deg[p]==0) que.push(p);
            }
        }
    }
};

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

    string s;
    cin >> s;
    int n = s.size();
    bool allSame = true;
    for (int i = 1; i < n; i++) if(s[i] != s[0]) { allSame = false; break; }

    if(allSame){
        int m = n / 2;
        ll ans = (ll) m * (n - m);
        cout << ans << endl;
        return 0;
    }

    SuffixAutomaton sa(n);
    for (int i = 0; i < n; i++) sa.extend(s[i], i);
    sa.merge_occurrences();

    ll ans = 0;
    int sz = sa.size;
    for (int i = 1; i < sz; i++){
        int Lmin = sa.st[ sa.st[i].link ].len + 1;
        int Lmax = sa.st[i].len;
        vector<int>& occ = sa.st[i].occ;
        int f = occ.size();
        int jlow = 0, jhigh = 0;
        for (int iocc = 0; iocc < f; iocc++){
            int base = occ[iocc];
            while(jlow < f && occ[jlow] < base + Lmin) jlow++;
            if(jhigh < jlow) jhigh = jlow;
            while(jhigh < f && occ[jhigh] <= base + Lmax) jhigh++;
            ans += (jhigh - jlow);
        }
    }
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 41720
final_rank: 7

code_snippet: #include <bits/stdc++.h>





namespace atcoder {

namespace internal {

std::vector<int> sa_naive(const std::vector<int>& s) {
    int n = int(s.size());
    std::vector<int> sa(n);
    std::iota(sa.begin(), sa.end(), 0);
    std::sort(sa.begin(), sa.end(), [&](int l, int r) {
        if (l == r) return false;
        while (l < n && r < n) {
            if (s[l] != s[r]) return s[l] < s[r];
            l++;
            r++;
        }
        return l == n;
    });
    return sa;
}

std::vector<int> sa_doubling(const std::vector<int>& s) {
    int n = int(s.size());
    std::vector<int> sa(n), rnk = s, tmp(n);
    std::iota(sa.begin(), sa.end(), 0);
    for (int k = 1; k < n; k *= 2) {
        auto cmp = [&](int x, int y) {
            if (rnk[x] != rnk[y]) return rnk[x] < rnk[y];
            int rx = x + k < n ? rnk[x + k] : -1;
            int ry = y + k < n ? rnk[y + k] : -1;
            return rx < ry;
        };
        std::sort(sa.begin(), sa.end(), cmp);
        tmp[sa[0]] = 0;
        for (int i = 1; i < n; i++) {
            tmp[sa[i]] = tmp[sa[i - 1]] + (cmp(sa[i - 1], sa[i]) ? 1 : 0);
        }
        std::swap(tmp, rnk);
    }
    return sa;
}

// SA-IS, linear-time suffix array construction
// Reference:
// G. Nong, S. Zhang, and W. H. Chan,
// Two Efficient Algorithms for Linear Time Suffix Array Construction
template <int THRESHOLD_NAIVE = 10, int THRESHOLD_DOUBLING = 40>
std::vector<int> sa_is(const std::vector<int>& s, int upper) {
    int n = int(s.size());
    if (n == 0) return {};
    if (n == 1) return {0};
    if (n == 2) {
        if (s[0] < s[1]) {
            return {0, 1};
        } else {
            return {1, 0};
        }
    }
    if (n < THRESHOLD_NAIVE) {
        return sa_naive(s);
    }
    if (n < THRESHOLD_DOUBLING) {
        return sa_doubling(s);
    }

    std::vector<int> sa(n);
    std::vector<bool> ls(n);
    for (int i = n - 2; i >= 0; i--) {
        ls[i] = (s[i] == s[i + 1]) ? ls[i + 1] : (s[i] < s[i + 1]);
    }
    std::vector<int> sum_l(upper + 1), sum_s(upper + 1);
    for (int i = 0; i < n; i++) {
        if (!ls[i]) {
            sum_s[s[i]]++;
        } else {
            sum_l[s[i] + 1]++;
        }
    }
    for (int i = 0; i <= upper; i++) {
        sum_s[i] += sum_l[i];
        if (i < upper) sum_l[i + 1] += sum_s[i];
    }

    auto induce = [&](const std::vector<int>& lms) {
        std::fill(sa.begin(), sa.end(), -1);
        std::vector<int> buf(upper + 1);
        std::copy(sum_s.begin(), sum_s.end(), buf.begin());
        for (auto d : lms) {
            if (d == n) continue;
            sa[buf[s[d]]++] = d;
        }
        std::copy(sum_l.begin(), sum_l.end(), buf.begin());
        sa[buf[s[n - 1]]++] = n - 1;
        for (int i = 0; i < n; i++) {
            int v = sa[i];
            if (v >= 1 && !ls[v - 1]) {
                sa[buf[s[v - 1]]++] = v - 1;
            }
        }
        std::copy(sum_l.begin(), sum_l.end(), buf.begin());
        for (int i = n - 1; i >= 0; i--) {
            int v = sa[i];
            if (v >= 1 && ls[v - 1]) {
                sa[--buf[s[v - 1] + 1]] = v - 1;
            }
        }
    };

    std::vector<int> lms_map(n + 1, -1);
    int m = 0;
    for (int i = 1; i < n; i++) {
        if (!ls[i - 1] && ls[i]) {
            lms_map[i] = m++;
        }
    }
    std::vector<int> lms;
    lms.reserve(m);
    for (int i = 1; i < n; i++) {
        if (!ls[i - 1] && ls[i]) {
            lms.push_back(i);
        }
    }

    induce(lms);

    if (m) {
        std::vector<int> sorted_lms;
        sorted_lms.reserve(m);
        for (int v : sa) {
            if (lms_map[v] != -1) sorted_lms.push_back(v);
        }
        std::vector<int> rec_s(m);
        int rec_upper = 0;
        rec_s[lms_map[sorted_lms[0]]] = 0;
        for (int i = 1; i < m; i++) {
            int l = sorted_lms[i - 1], r = sorted_lms[i];
            int end_l = (lms_map[l] + 1 < m) ? lms[lms_map[l] + 1] : n;
            int end_r = (lms_map[r] + 1 < m) ? lms[lms_map[r] + 1] : n;
            bool same = true;
            if (end_l - l != end_r - r) {
                same = false;
            } else {
                while (l < end_l) {
                    if (s[l] != s[r]) {
                        break;
                    }
                    l++;
                    r++;
                }
                if (l == n || s[l] != s[r]) same = false;
            }
            if (!same) rec_upper++;
            rec_s[lms_map[sorted_lms[i]]] = rec_upper;
        }

        auto rec_sa =
            sa_is<THRESHOLD_NAIVE, THRESHOLD_DOUBLING>(rec_s, rec_upper);

        for (int i = 0; i < m; i++) {
            sorted_lms[i] = lms[rec_sa[i]];
        }
        induce(sorted_lms);
    }
    return sa;
}

}  // namespace internal

std::vector<int> suffix_array(const std::vector<int>& s, int upper) {
    assert(0 <= upper);
    for (int d : s) {
        assert(0 <= d && d <= upper);
    }
    auto sa = internal::sa_is(s, upper);
    return sa;
}

template <class T> std::vector<int> suffix_array(const std::vector<T>& s) {
    int n = int(s.size());
    std::vector<int> idx(n);
    iota(idx.begin(), idx.end(), 0);
    sort(idx.begin(), idx.end(), [&](int l, int r) { return s[l] < s[r]; });
    std::vector<int> s2(n);
    int now = 0;
    for (int i = 0; i < n; i++) {
        if (i && s[idx[i - 1]] != s[idx[i]]) now++;
        s2[idx[i]] = now;
    }
    return internal::sa_is(s2, now);
}

std::vector<int> suffix_array(const std::string& s) {
    int n = int(s.size());
    std::vector<int> s2(n);
    for (int i = 0; i < n; i++) {
        s2[i] = s[i];
    }
    return internal::sa_is(s2, 255);
}

// Reference:
// T. Kasai, G. Lee, H. Arimura, S. Arikawa, and K. Park,
// Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its
// Applications
template <class T>
std::vector<int> lcp_array(const std::vector<T>& s,
                           const std::vector<int>& sa) {
    int n = int(s.size());
    assert(n >= 1);
    std::vector<int> rnk(n);
    for (int i = 0; i < n; i++) {
        rnk[sa[i]] = i;
    }
    std::vector<int> lcp(n - 1);
    int h = 0;
    for (int i = 0; i < n; i++) {
        if (h > 0) h--;
        if (rnk[i] == 0) continue;
        int j = sa[rnk[i] - 1];
        for (; j + h < n && i + h < n; h++) {
            if (s[j + h] != s[i + h]) break;
        }
        lcp[rnk[i] - 1] = h;
    }
    return lcp;
}

std::vector<int> lcp_array(const std::string& s, const std::vector<int>& sa) {
    int n = int(s.size());
    std::vector<int> s2(n);
    for (int i = 0; i < n; i++) {
        s2[i] = s[i];
    }
    return lcp_array(s2, sa);
}

// Reference:
// D. Gusfield,
// Algorithms on Strings, Trees, and Sequences: Computer Science and
// Computational Biology
template <class T> std::vector<int> z_algorithm(const std::vector<T>& s) {
    int n = int(s.size());
    if (n == 0) return {};
    std::vector<int> z(n);
    z[0] = 0;
    for (int i = 1, j = 0; i < n; i++) {
        int& k = z[i];
        k = (j + z[j] <= i) ? 0 : std::min(j + z[j] - i, z[i - j]);
        while (i + k < n && s[k] == s[i + k]) k++;
        if (j + z[j] < i + z[i]) j = i;
    }
    z[0] = n;
    return z;
}

std::vector<int> z_algorithm(const std::string& s) {
    int n = int(s.size());
    std::vector<int> s2(n);
    for (int i = 0; i < n; i++) {
        s2[i] = s[i];
    }
    return z_algorithm(s2);
}

}  // namespace atcoder



std::string reversed(std::string S) {
    std::reverse(S.begin(), S.end());
    return S;
}

int main() {
    std::string S;
    std::cin >> S;
    auto rec{[&](auto rec, int L, int R) -> long long {
        if (L + 1 >= R) return 0LL;
        int M{(L + R) / 2};
        long long res{};
        std::string FR{S.substr(L, M - L)}, BK{S.substr(M, R - M)};
        {
            std::string T{reversed(FR) + reversed(BK)};
            std::vector<int> Z1{atcoder::z_algorithm(BK)}, Z2{atcoder::z_algorithm(T)};
            for (int i{2} ; i < (int)BK.size() ; i++) {
                int z1{Z1[i]};
                int z2{Z2[FR.size() + BK.size() - i]};
                int max1{std::min(i - 1, z1)};
                int max2{std::min(i - 1, z2)};
                res += std::max(0, max1 + max2 - i + 1);
            }
        }
        {
            std::vector<int> Z1{atcoder::z_algorithm(reversed(FR))}, Z2{atcoder::z_algorithm(BK + FR)};
            for (int i{2} ; i < (int)FR.size() ; i++) {
                int z1{Z1[i]}, z2{Z2[BK.size() + FR.size() - i]};
                int max1{std::min(i - 1, z1)};
                int max2{std::min(i - 1, z2)};
                res += std::max(0, max1 + max2 - i + 1);
            }
            for (int i{} ; i < (int)FR.size() ; i++) {
                if (Z2[BK.size() + i] >= (int)FR.size() - i) res++;
            }
        }
        res += rec(rec, L, M);
        res += rec(rec, M, R);
        return res;
    }};
    std::cout << rec(rec, 0, (int)S.size()) << '\n';
}
accuracy: 1
time_ms: 40
memory_kb: 4440
final_rank: 1

code_snippet: #pragma GCC optimize("O3")

// RollingHash
// https://www.acmicpc.net/problem/1605
#include<bits/stdc++.h>

using namespace std;

// https://qiita.com/recuraki/items/652f97f5330fde231ddb#%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E8%A1%9D%E7%AA%81%E6%94%BB%E6%92%83%E3%81%AE%E3%83%8F%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%E3%81%8B%E3%82%89%E8%BA%AB%E3%82%92%E5%AE%88%E3%82%8B%E6%96%B9%E6%B3%95
#include <chrono>
struct custom_hash {
    static uint64_t splitmix64(uint64_t x) {
        // http://xorshift.di.unimi.it/splitmix64.c
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};

// Safer-Faster-RollingHash
// https://qiita.com/keymoon/items/11fac5627672a6d6a9f6
// https://atcoder.jp/contests/abc141/submissions/7717102
typedef unsigned long long int ull;

#define MAXLEN 500005

const ull MASK30 = (1ull << 30) - 1;
const ull MASK31 = (1ull << 31) - 1;
const ull MOD = (1ull << 61) - 1;
const ull MASK61 = MOD;
const ull POSITIVIZER = MOD * 4;

//mod 2^61-1
ull CalcMod(ull x)
{
    ull xu = x >> 61;
    ull xd = x & MASK61;
    ull res = xu + xd;
    if (res >= MOD) res -= MOD;
    return res;
}

//a*b mod 2^61-1
ull Mul(ull a, ull b)
{
    ull au = a >> 31;
    ull ad = a & MASK31;
    ull bu = b >> 31;
    ull bd = b & MASK31;
    ull mid = ad * bu + au * bd;
    ull midu = mid >> 30;
    ull midd = mid & MASK30;
    return CalcMod(au * bu * 2 + midu + (midd << 31) + ad * bd);
}

ull hBase;
vector<ull> powMemo;
void genBase(mt19937_64 &eg){
  hBase=0;
  while(hBase==0){
    hBase=CalcMod((ull)eg());
  }

  powMemo.resize(MAXLEN);
  powMemo[0]=1;
  for(int i=1;i<MAXLEN;i++){
    powMemo[i]=Mul(powMemo[i-1],hBase);
  }
}

vector<ull> genHash(string s){
  vector<ull> res={0};
  ull cur=0;
  for(auto &nx : s){
    cur=Mul(cur,hBase);
    cur=CalcMod(cur+nx);
    res.push_back(cur);
  }
  return res;
}

// substr [l,r) (0-indexed)
ull subHash(int l,int r,vector<ull> &hv){
  return CalcMod(hv[r] + POSITIVIZER - Mul(hv[l], powMemo[r-l]));
}

int main(){
  random_device seed_gen;
  mt19937_64 engine(seed_gen());

  genBase(engine);

  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  {
    string s;
    cin >> s;

    long long res=0;
    int l=s.size();
    vector<ull> hv=genHash(s);
    for(int u=1;u<=(l/2);u++){
      bool pre=false;
      int f=(u-1);
      while(f+u<l){
        int s=(f+u);
        int lef=1,rig=u;
        while(lef<=rig){
          int te=(lef+rig)/2;
          if(subHash(f+1-te,f+1,hv)==subHash(s+1-te,s+1,hv)){lef=te+1;}
          else{rig=te-1;}
        }
        if(rig==u){
          // match
          if(pre){res+=u;}
          else{res++;}
          pre=true;
          f=s;
        }
        else{
          if(pre){
            int ulef=1,urig=u;
            while(ulef<=urig){
              int te=(ulef+urig)/2;
              if(subHash(f+1-u,f+1+te-u,hv)==subHash(f+1,f+1+te,hv)){ulef=te+1;}
              else{urig=te-1;}
            }
            res+=urig;
          }
          pre=false;
          f=s-rig;
        }
      }
      if(pre){
        int ulef=1,urig=u;
        while(ulef<=urig){
          int te=(ulef+urig)/2;
          if(f+1+te>l){urig=te-1; continue;}
          if(subHash(f+1-u,f+1+te-u,hv)==subHash(f+1,f+1+te,hv)){ulef=te+1;}
          else{urig=te-1;}
        }
        res+=urig;
      }
    }
    cout << res << "\n";
  }
}
accuracy: 1
time_ms: 60
memory_kb: 8148
final_rank: 3

code_snippet: #include <bits/stdc++.h>

using std::vector;
using std::array;
using std::pair;
using std::tuple;

using ll = long long;

vector<int> suffix_array(const std::string& s) {
    const int n = (int)s.size();
    vector<int> sa(n);
    std::iota(sa.begin(), sa.end(), 0);
    std::sort(sa.begin(), sa.end(), [&](const int& a, const int& b) {
        if (s[a] == s[b]) return (a > b);
        return (s[a] < s[b]);
    });
    vector<int> classes(n), c(n), cnt(n);
    for (int i = 0; i < n; i++) {
        c[i] = s[i];
    }
    for (int len = 1; len < n; len <<= 1) {
        for (int i = 0; i < n; i++) {
            if (i > 0 && c[sa[i - 1]] == c[sa[i]] && sa[i - 1] + len < n &&
                c[sa[i - 1] + len / 2] == c[sa[i] + len / 2]) {
                classes[sa[i]] = classes[sa[i - 1]];
            } else {
                classes[sa[i]] = i;
            }
        }
        std::iota(cnt.begin(), cnt.end(), 0);
        std::copy(sa.begin(), sa.end(), c.begin());
        for (int i = 0; i < n; i++) {
            int s1 = c[i] - len;
            if (s1 >= 0) sa[cnt[classes[s1]]++] = s1;
        }
        std::swap(classes, c);
    }
    return sa;
}

vector<int> lcp_array(const std::string& s, const vector<int>& sa) {
    int n = (int)s.size();
    assert(n >= 1);
    vector<int> rnk(n);
    for (int i = 0; i < n; i++) {
        rnk[sa[i]] = i;
    }
    vector<int> lcp(n - 1);
    int h = 0;
    for (int i = 0; i < n; i++) {
        if (h > 0) h--;
        if (rnk[i] == 0) continue;
        int j = sa[rnk[i] - 1];
        for (; j + h < n && i + h < n; h++) {
            if (s[j + h] != s[i + h]) break;
        }
        lcp[rnk[i] - 1] = h;
    }
    return lcp;
}

template <class F>
struct Fixed : private F {
    explicit Fixed(F&& f) : F(std::forward<F>(f)) {}
    template <class... Args> decltype(auto) operator()(Args&&... args) const {
        return F::operator()(*this, std::forward<Args>(args)...);
    }
};

template <class F>
decltype(auto) fixed(F&& f) {
    return Fixed<F>(std::forward<F>(f));
}

struct Fenwick {
    int size;
    vector<int> data;
    explicit Fenwick(const int n) : size(n), data(n + 1) {}
    void add(int i, const int x) {
        i += 1;
        while (i <= size) {
            data[i] += x;
            i += i & -i;
        }
    }
    int pref(int i) const {
        int x = 0;
        while (i > 0) {
            x += data[i];
            i -= i & -i;
        }
        return x;
    }
    int fold(const int l, const int r) const {
        return pref(r) - pref(l);
    }
};

struct Counter {
    vector<int> list;
    Fenwick fen;
    explicit Counter(const vector<int>& vec) : list(vec), fen(vec.size()) {
        std::sort(list.begin(), list.end());
    }
    void add(const int x) {
        const int i = std::lower_bound(list.begin(), list.end(), x) - list.begin();
        fen.add(i, 1);
    }
    int count(const int l, const int r) const {
        const int i = std::lower_bound(list.begin(), list.end(), l) - list.begin();
        const int j = std::lower_bound(list.begin(), list.end(), r + 1) - list.begin();
        return fen.fold(i, j);
    }
};

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::string str;
    std::cin >> str;
    const int N = (int)str.size();
    const auto A = suffix_array(str);
    const auto B = lcp_array(str, A);
    ll ans = 0;
    fixed([&](auto&& dfs, const int lb, const int ub) -> void {
        const int n = ub - lb;
        if (n == 1) {
            return;
        }
        const int mid = (lb + ub) / 2;
        const int nl = mid - lb;
        vector<pair<int, int>> b(n);
        b[nl - 1].first = b[nl].first = B[mid - 1];
        for (int i = nl - 2; i >= 0; --i) {
            b[i].first = std::min(b[i + 1].first, B[lb + i]);
        }
        for (int i = nl + 1; i < n; ++i) {
            b[i].first = std::min(b[i - 1].first, B[lb + i - 1]);
        }
        for (int i = 0; i < n; ++i) {
            b[i].second = lb + i;
        }
        std::sort(b.rbegin(), b.rend());
        Counter cl(std::vector<int>(A.begin() + lb, A.begin() + mid));
        Counter cr(std::vector<int>(A.begin() + mid, A.begin() + ub));
        for (const auto& p : b) {
            const int min = p.first;
            const int i = p.second;
            if (i >= mid) {
                ans += cl.count(A[i] - min, A[i] + min);
                cr.add(A[i]);
            } else {
                ans += cr.count(A[i] - min, A[i] + min);
                cl.add(A[i]);
            }
        }
        dfs(lb, mid);
        dfs(mid, ub);
    })(0, N);
    std::cout << ans << '\n';
    return 0;
}
accuracy: 1
time_ms: 280
memory_kb: 6900
final_rank: 5

code_snippet: #include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#define _GLIBCXX_DEBUG
using namespace std;
using std::cout;
using std::cin;
using std::endl;
using ll=long long;
using ld=long double;
ll ILL=2167167167167167167;
const int INF=100000000;
const ll mod=1e9+7;
#define rep(i,a) for (ll i=0;i<a;i++)
#define all(p) p.begin(),p.end()
template<class T> using _pq = priority_queue<T, vector<T>, greater<T>>;
template<class T> ll LB(vector<T> &v,T a){return lower_bound(v.begin(),v.end(),a)-v.begin();}
template<class T> ll UB(vector<T> &v,T a){return upper_bound(v.begin(),v.end(),a)-v.begin();}
template<class T> bool chmin(T &a,const T &b){if(a>b){a=b;return 1;}else return 0;}
template<class T> bool chmax(T &a,const T &b){if(a<b){a=b;return 1;}else return 0;}
template<class T> void So(vector<T> &v) {sort(v.begin(),v.end());}
template<class T> void Sore(vector<T> &v) {sort(v.begin(),v.end(),[](T x,T y){return x>y;});}
void yneos(bool a){if(a) cout<<"Yes\n"; else cout<<"No\n";}
template<class T> void vec_out(vector<T> &p){for(int i=0;i<(int)(p.size());i++){if(i) cout<<" ";cout<<p[i];}cout<<"\n";}


// CUT begin
// Suffix array algorithms from AtCoder Library
// Document: <https://atcoder.github.io/ac-library/master/document_ja/string.html>
namespace internal {

std::vector<int> sa_naive(const std::vector<int>& s) {
    int n = int(s.size());
    std::vector<int> sa(n);
    std::iota(sa.begin(), sa.end(), 0);
    std::sort(sa.begin(), sa.end(), [&](int l, int r) {
        if (l == r) return false;
        while (l < n && r < n) {
            if (s[l] != s[r]) return s[l] < s[r];
            l++, r++;
        }
        return l == n;
    });
    return sa;
}

std::vector<int> sa_doubling(const std::vector<int>& s) {
    int n = int(s.size());
    std::vector<int> sa(n), rnk = s, tmp(n);
    std::iota(sa.begin(), sa.end(), 0);
    for (int k = 1; k < n; k *= 2) {
        auto cmp = [&](int x, int y) {
            if (rnk[x] != rnk[y]) return rnk[x] < rnk[y];
            int rx = x + k < n ? rnk[x + k] : -1;
            int ry = y + k < n ? rnk[y + k] : -1;
            return rx < ry;
        };
        std::sort(sa.begin(), sa.end(), cmp);
        tmp[sa[0]] = 0;
        for (int i = 1; i < n; i++) { tmp[sa[i]] = tmp[sa[i - 1]] + (cmp(sa[i - 1], sa[i]) ? 1 : 0); }
        std::swap(tmp, rnk);
    }
    return sa;
}

// SA-IS, linear-time suffix array construction
// Reference:
// G. Nong, S. Zhang, and W. H. Chan,
// Two Efficient Algorithms for Linear Time Suffix Array Construction
template <int THRESHOLD_NAIVE = 10, int THRESHOLD_DOUBLING = 40> std::vector<int> sa_is(const std::vector<int>& s, int upper) {
    int n = int(s.size());
    if (n == 0) return {};
    if (n == 1) return {0};
    if (n == 2) {
        if (s[0] < s[1]) {
            return {0, 1};
        } else {
            return {1, 0};
        }
    }
    if (n < THRESHOLD_NAIVE) { return sa_naive(s); }
    if (n < THRESHOLD_DOUBLING) { return sa_doubling(s); }

    std::vector<int> sa(n);
    std::vector<bool> ls(n);
    for (int i = n - 2; i >= 0; i--) { ls[i] = (s[i] == s[i + 1]) ? ls[i + 1] : (s[i] < s[i + 1]); }
    std::vector<int> sum_l(upper + 1), sum_s(upper + 1);
    for (int i = 0; i < n; i++) {
        if (!ls[i]) {
            sum_s[s[i]]++;
        } else {
            sum_l[s[i] + 1]++;
        }
    }
    for (int i = 0; i <= upper; i++) {
        sum_s[i] += sum_l[i];
        if (i < upper) sum_l[i + 1] += sum_s[i];
    }

    auto induce = [&](const std::vector<int>& lms) {
        std::fill(sa.begin(), sa.end(), -1);
        std::vector<int> buf(upper + 1);
        std::copy(sum_s.begin(), sum_s.end(), buf.begin());
        for (auto d : lms) {
            if (d == n) continue;
            sa[buf[s[d]]++] = d;
        }
        std::copy(sum_l.begin(), sum_l.end(), buf.begin());
        sa[buf[s[n - 1]]++] = n - 1;
        for (int i = 0; i < n; i++) {
            int v = sa[i];
            if (v >= 1 && !ls[v - 1]) { sa[buf[s[v - 1]]++] = v - 1; }
        }
        std::copy(sum_l.begin(), sum_l.end(), buf.begin());
        for (int i = n - 1; i >= 0; i--) {
            int v = sa[i];
            if (v >= 1 && ls[v - 1]) { sa[--buf[s[v - 1] + 1]] = v - 1; }
        }
    };

    std::vector<int> lms_map(n + 1, -1);
    int m = 0;
    for (int i = 1; i < n; i++) {
        if (!ls[i - 1] && ls[i]) { lms_map[i] = m++; }
    }
    std::vector<int> lms;
    lms.reserve(m);
    for (int i = 1; i < n; i++) {
        if (!ls[i - 1] && ls[i]) { lms.push_back(i); }
    }

    induce(lms);

    if (m) {
        std::vector<int> sorted_lms;
        sorted_lms.reserve(m);
        for (int v : sa) {
            if (lms_map[v] != -1) sorted_lms.push_back(v);
        }
        std::vector<int> rec_s(m);
        int rec_upper = 0;
        rec_s[lms_map[sorted_lms[0]]] = 0;
        for (int i = 1; i < m; i++) {
            int l = sorted_lms[i - 1], r = sorted_lms[i];
            int end_l = (lms_map[l] + 1 < m) ? lms[lms_map[l] + 1] : n;
            int end_r = (lms_map[r] + 1 < m) ? lms[lms_map[r] + 1] : n;
            bool same = true;
            if (end_l - l != end_r - r) {
                same = false;
            } else {
                while (l < end_l) {
                    if (s[l] != s[r]) { break; }
                    l++;
                    r++;
                }
                if (l == n || s[l] != s[r]) same = false;
            }
            if (!same) rec_upper++;
            rec_s[lms_map[sorted_lms[i]]] = rec_upper;
        }

        auto rec_sa = sa_is<THRESHOLD_NAIVE, THRESHOLD_DOUBLING>(rec_s, rec_upper);

        for (int i = 0; i < m; i++) { sorted_lms[i] = lms[rec_sa[i]]; }
        induce(sorted_lms);
    }
    return sa;
}

} // namespace internal

std::vector<int> suffix_array(const std::vector<int>& s, int upper) {
    assert(0 <= upper);
    for (int d : s) { assert(0 <= d && d <= upper); }
    auto sa = internal::sa_is(s, upper);
    return sa;
}

template <class T> std::vector<int> suffix_array(const std::vector<T>& s) {
    int n = int(s.size());
    std::vector<int> idx(n);
    iota(idx.begin(), idx.end(), 0);
    sort(idx.begin(), idx.end(), [&](int l, int r) { return s[l] < s[r]; });
    std::vector<int> s2(n);
    int now = 0;
    for (int i = 0; i < n; i++) {
        if (i && s[idx[i - 1]] != s[idx[i]]) now++;
        s2[idx[i]] = now;
    }
    return internal::sa_is(s2, now);
}

std::vector<int> suffix_array(const std::string& s) {
    int n = int(s.size());
    std::vector<int> s2(n);
    for (int i = 0; i < n; i++) { s2[i] = s[i]; }
    return internal::sa_is(s2, 255);
}

// Reference:
// T. Kasai, G. Lee, H. Arimura, S. Arikawa, and K. Park,
// Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its
// Applications
template <class T> std::vector<int> lcp_array(const std::vector<T>& s, const std::vector<int>& sa) {
    int n = int(s.size());
    assert(n >= 1);
    std::vector<int> rnk(n);
    for (int i = 0; i < n; i++) { rnk[sa[i]] = i; }
    std::vector<int> lcp(n - 1);
    int h = 0;
    for (int i = 0; i < n; i++) {
        if (h > 0) h--;
        if (rnk[i] == 0) continue;
        int j = sa[rnk[i] - 1];
        for (; j + h < n && i + h < n; h++) {
            if (s[j + h] != s[i + h]) break;
        }
        lcp[rnk[i] - 1] = h;
    }
    return lcp;
}

std::vector<int> lcp_array(const std::string& s, const std::vector<int>& sa) {
    int n = int(s.size());
    std::vector<int> s2(n);
    for (int i = 0; i < n; i++) { s2[i] = s[i]; }
    return lcp_array(s2, sa);
}

// Count keyword occurence in str
// Complexity: O(min(|str|, |keyword|) * lg |str|)
int count_keyword_occurence(const std::string& str, const std::vector<int>& suffarr, const std::string& keyword) {
    const int n = str.size(), m = keyword.size();
    assert(n == suffarr.size());
    if (n < m) return 0;
    auto f1 = [&](int h) {
        for (int j = 0; h + j < n and j < m; j++) {
            if (str[h + j] < keyword[j]) return true;
            if (str[h + j] > keyword[j]) return false;
        }
        return n - h < m;
    };
    auto f2 = [&](int h) {
        for (int j = 0; h + j < n and j < m; j++) {
            // if (str[h + j] < keyword[j]) return true;
            if (str[h + j] > keyword[j]) return false;
        }
        return true;
    };
    const auto L = std::partition_point(suffarr.begin(), suffarr.end(), f1);
    const auto R = std::partition_point(L, suffarr.end(), f2);
    return std::distance(L, R);
    // return std::vector<int>(L, R); // if you need occurence positions
}
// CUT begin
// Range Minimum Query for static sequence by sparse table
// Complexity: O(NlogN) for precalculation, O(1) per query
template <typename T> struct StaticRMQ {
    inline T func(const T &l, const T &r) const noexcept { return std::min<T>(l, r); }
    int N, lgN;
    T defaultT;
    std::vector<std::vector<T>> data;
    std::vector<int> lgx_table;
    StaticRMQ() = default;
    StaticRMQ(const std::vector<T> &sequence, T defaultT) : N(sequence.size()), defaultT(defaultT) {
        lgx_table.resize(N + 1);
        for (int i = 2; i < N + 1; i++) lgx_table[i] = lgx_table[i >> 1] + 1;
        lgN = lgx_table[N] + 1;
        data.assign(lgN, std::vector<T>(N, defaultT));
        data[0] = sequence;
        for (int d = 1; d < lgN; d++) {
            for (int i = 0; i + (1 << d) <= N; i++) {
                data[d][i] = func(data[d - 1][i], data[d - 1][i + (1 << (d - 1))]);
            }
        }
    }
    T get(int l, int r) const { // [l, r), 0-indexed
        assert(l >= 0 and r <= N);
        if (l >= r) return defaultT;
        int d = lgx_table[r - l];
        return func(data[d][l], data[d][r - (1 << d)]);
    }
};
struct LongestCommonPrefix {
    const int N;
    std::vector<int> sainv; // len = N
    StaticRMQ<int> rmq;
    LongestCommonPrefix(const std::string s) : N(s.size()) {
        auto sa = suffix_array(s);
        auto lcp = lcp_array(s, sa);
        sainv.resize(N);
        for (int i = 0; i < N; i++) sainv[sa[i]] = i;
        rmq = {lcp, N};
    }
    int lcplen(int l1, int l2) const {
        if (l1 == l2) return N - l1;
        if (l1 == N or l2 == N) return 0;
        l1 = sainv[l1], l2 = sainv[l2];
        if (l1 > l2) std::swap(l1, l2);
        return rmq.get(l1, l2);
    }
};

// CUT begin
// Lyndon factorization based on Duval's algorithm
// **NOT VERIFIED YET**
// Reference:
// [1] K. T. Chen, R. H. Fox, R. C. Lyndon,
//     "Free Differential Calculus, IV. The Quotient Groups of the Lower Central Series,"
//     Annals of Mathematics, 81-95, 1958.
// [2] J. P. Duval, "Factorizing words over an ordered alphabet,"
//     Journal of Algorithms, 4(4), 363-381, 1983.
// - https://cp-algorithms.com/string/lyndon_factorization.html
// - https://qiita.com/nakashi18/items/66882bd6e0127174267a
template <typename T> std::vector<std::pair<int, int>> lyndon_factorization(const std::vector<T> &S) {
    const int N = S.size();
    std::vector<std::pair<int, int>> ret;
    for (int l = 0; l < N;) {
        int i = l, j = i + 1;
        while (j < N and S[i] <= S[j]) i = (S[i] == S[j] ? i + 1 : l), j++;
        ret.emplace_back(l, j - i), l += j - i;
    }
    return ret;
}

std::vector<std::pair<int, int>> lyndon_factorization(const std::string &s) {
    const int N = int(s.size());
    std::vector<int> v(N);
    for (int i = 0; i < N; i++) v[i] = s[i];
    return lyndon_factorization<int>(v);
}

// Compute the longest Lyndon prefix for each suffix s[i:N]
// (Our implementation is $O(N \log N)$)
// Example:
// - `teletelepathy` -> [1,4,1,2,1,4,1,2,1,4,1,2,1]
// Reference:
// [1] H. Bannai et al., "The "Runs" Theorem,"
// SIAM Journal on Computing, 46.5, 1501-1514, 2017.
template <typename String>
std::vector<int> longest_lyndon_prefixes(const String &s, const LongestCommonPrefix &rh) {
    const int N = s.size();
    std::vector<std::pair<int, int>> st{{N, N}};
    std::vector<int> ret(N);
    for (int i = N - 1, j = i; i >= 0; i--, j = i) {
        while (st.size() > 1) {
            int iv = st.back().first, jv = st.back().second;
            int l = rh.lcplen(i, iv);
            if (!(iv + l < N and s[i + l] < s[iv + l])) break;
            j = jv;
            st.pop_back();
        }
        st.emplace_back(i, j);
        ret[i] = j - i + 1;
    }
    return ret;
}

// Compute all runs in given string
// Complexity: $O(N \log N)$ in this implementation (Theoretically $O(N)$ achievable)
// N = 2e5 -> ~800 ms
// Reference:
// [1] H. Bannai et al., "The "Runs" Theorem,"
// SIAM Journal on Computing, 46.5, 1501-1514, 2017.
std::vector<std::tuple<int, int, int>> run_enumerate(std::string s) {
    if (s.empty()) return {};
    LongestCommonPrefix rh(s);
    std::reverse(s.begin(), s.end());
    LongestCommonPrefix rrev(s);
    std::reverse(s.begin(), s.end());
    auto t = s;
    auto lo = *std::min_element(s.begin(), s.end()), hi = *std::max_element(s.begin(), s.end());
    for (auto &c : t) c = hi - (c - lo);
    auto l1 = longest_lyndon_prefixes(s, rh), l2 = longest_lyndon_prefixes(t, rh);
    int N = s.size();
    std::vector<std::tuple<int, int, int>> ret;
    for (int i = 0; i < N; i++) {
        int j = i + l1[i], L = i - rrev.lcplen(N - i, N - j), R = j + rh.lcplen(i, j);
        if (R - L >= (j - i) * 2) ret.emplace_back(j - i, L, R);

        if (l1[i] != l2[i]) {
            j = i + l2[i], L = i - rrev.lcplen(N - i, N - j), R = j + rh.lcplen(i, j);
            if (R - L >= (j  - i) * 2) ret.emplace_back(j - i, L, R);
        }
    }
    std::sort(ret.begin(), ret.end());
    ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
    return ret;
}

//https://judge.yosupo.jp/submission/41769

void solve();
// oddloop
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t=1;
	//cin>>t;
	rep(i,t) solve();
}

void solve(){
	string S;
	cin>>S;
	auto ret=run_enumerate(S);
	ll ans=0;
	for(auto x:ret){
		ll t,l,r;
		tie(t,l,r)=x;
		//cout<<t<<" "<<l<<" "<<r<<"\n";
		ll len=r-l,c=1;
		while(c*t*2<=len) ans+=len+1-c*t*2,c++;
	}
	cout<<ans<<"\n";
}
accuracy: 1
time_ms: 20
memory_kb: 22076
final_rank: 4

code_snippet: #include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <vector>
#include <numeric>
#include <algorithm>
#include <queue>
#include <string>
#include <random>
#include <array>
#include <climits>
#include <map>
#include <cassert>
std::vector<int> longest_common_prefix_table(const std::string& str) {
	const int n = str.size();
	std::vector<int> result(n);
	int left{ 1 };
	int right{ 1 };
	for (auto i = 1; i < n; ++i) {
		if (right < i) {
			left = i;
			right = i;
		}
		if (right <= i + result[i - left]) {
			int len = right - i;
			while (right < n && str[right] == str[len]) {
				++len;
				++right;
			}
			result[i] = len;
			left = i;
		}
		else {
			result[i] = result[i - left];
		}
	}
	result[0] = n;
	return result;
}
std::vector<int> longest_common_prefix_table(const std::string& objective, const std::string& pattern) {
	const int n = objective.size();
	std::vector<int> result(n);
	int left{ 0 };
	int right{ 0 };
	const auto lcp = longest_common_prefix_table(pattern);
	for (auto i = 0; i < n; ++i) {
		if (right < i) {
			left = i;
			right = i;
		}
		if (i - left == lcp.size() || right <= i + lcp[i - left]) {
			int len = right - i;
			while (len < pattern.size() && right < n && pattern[len] == objective[right]) {
				++len;
				++right;
			}
			result[i] = len;
			left = i;
		}
		else {
			result[i] = lcp[i - left];
		}
	}
	return result;
}

long long int brute(const std::string& str) {
	int result{ 0 };
	for (auto i = 0; i < str.size(); ++i) {
		for (auto len = 1; i + len * 2 <= str.size(); ++len) {
			bool same = true;
			for (auto j = 0; j < len; ++j) {
				if (str[i + j] != str[i + j + len]) {
					same = false; break;
				}
			}
			if (same) {
				++result;
			}
		}
	}
	return result;
}
long long int solve(const std::string str) {
	if (str.size() < 10) {
		return brute(str);
	}
	const int n = str.size();
	const auto left = str.substr(0, n / 2);
	const auto right = str.substr(n / 2);
	auto left_reverse = left; std::reverse(left_reverse.begin(), left_reverse.end());
	auto right_reverse = right; std::reverse(right_reverse.begin(), right_reverse.end());
	auto ll = longest_common_prefix_table(left_reverse, left_reverse); std::reverse(ll.begin(), ll.end());
	const auto rr = longest_common_prefix_table(right, right);
	const auto lr = longest_common_prefix_table(left, right);
	auto rl = longest_common_prefix_table(right_reverse, left_reverse); std::reverse(rl.begin(), rl.end());
	long long int result{ solve(left) + solve(right) };
	if (lr[0] == left.size()) {
		++result;
	}
	for (auto i = 0; i + 1 < left.size(); ++i) {
		const int rest = left.size() - i - 1;
		const auto l = std::min(rest - 1, ll[i]);
		const auto r = lr[i + 1];
		if (r == 0) continue;
		if (l + r < rest) continue;
		result += (l + r + 1) - rest;
	}
	for (auto i = 1; i + 1 < right.size(); ++i) {
		const auto rest = i + 1;
		const auto l = std::min(rest - 1, rl[i]);
		const auto r = std::min(rest - 1, rr[i + 1]);
		if (l + r < rest) continue;
		result += (l + r + 1) - rest;
	}
	return result;
}
int main() {
	std::string str; std::cin >> str;
	const auto result = solve(str);
	std::cout << result << std::endl;
}
accuracy: 1
time_ms: 30
memory_kb: 5540
final_rank: 2

code_snippet: #include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <tuple>


std::vector<int> z_algorithm(const std::string& S) {
    int n = S.size();
    std::vector<int> res(n, 0);
    res[0] = n;
    int pbegin = 1, pend = 1;
    for (int i = 1; i < n; i++) {
        if (i < pend) {
            res[i] = res[i - pbegin];
            if (pend > i + res[i]) continue;
            res[i] = pend - i;
            pbegin = i;
        }
        else {
            pbegin = pend = i;
        }
        while (true) {
            if (pend == n) break;
            if (S[pend] != S[res[i]]) break;
            res[i]++;
            pend++;
        }
    }
    return res;
}


struct Run {
    int period;
    int begin;
    int length;
};
std::vector<Run> run_enumerate(std::string S) {
    std::vector<std::pair<int, int>> ranges;
    ranges.push_back(std::make_pair(0, (int)S.size()));
    std::vector<Run> res;
    auto run_order = [](Run l, Run r) {
        return std::make_tuple(l.period, l.begin, l.length)
            < std::make_tuple(r.period, r.begin, r.length);
    };
    auto run_order2 = [](Run l, Run r) {
        return std::make_tuple(l.begin, l.length, l.period)
            < std::make_tuple(r.begin, r.length, r.period);
    };
    while (ranges.size()) {
        auto range = ranges.back();
        ranges.pop_back();
        int len = range.second - range.first;
        if (range.second - range.first <= 1) continue;

        std::string tg = S.substr(range.first, len);

        int pos_offset = range.first;

        int l_size = tg.size() / 2;
        int r_size = tg.size() - l_size;

        ranges.push_back(std::make_pair(pos_offset + l_size, pos_offset + l_size + r_size));
        ranges.push_back(std::make_pair(pos_offset, pos_offset + l_size));

        std::string tg_tst = tg.substr(l_size) + tg;
        auto z_tst = z_algorithm(tg_tst);
        std::string tg_rsts = tg + tg.substr(0, l_size);
        std::reverse(tg_rsts.begin(), tg_rsts.end());
        auto z_rsts = z_algorithm(tg_rsts);
        for (int period = 1; period <= l_size; period++) {
            int run_l_len = std::min(l_size, z_rsts[period] + period);
            int run_r_len = std::min(r_size, z_tst[r_size + l_size - period]);
            if (run_l_len + run_r_len < period * 2) continue;
            res.push_back({ period, pos_offset + l_size - run_l_len, run_l_len + run_r_len });
        }
        for (int period = 1; period <= r_size; period++) {
            int run_r_len = std::min(r_size, z_tst[period] + period);
            int run_l_len = std::min(l_size, z_rsts[l_size + r_size - period]);
            if (run_l_len + run_r_len < period * 2) continue;
            res.push_back({ period, pos_offset + l_size - run_l_len, run_l_len + run_r_len });
        }
    }

    if (res.empty()) return res;

    std::sort(res.begin(), res.end(), run_order);
    int p = 0;
    for (int i = 1; i < res.size(); i++) {
        bool use = true;
        if (res[p].period == res[i].period) {
            if (res[p].begin + res[p].length > res[i].begin + res[i].period) {
                use = false;
                if (res[p].begin + res[p].length < res[i].begin + res[i].length) {
                    res[p].length = res[i].begin + res[i].length - res[p].begin;
                }
            }
        }
        if (use) { res[++p] = res[i]; }
    }
    res.resize(p + 1);

    return res;
}


using namespace std;
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
#define rep(i,n) for(int i=0; i<(n); i++)


int main(){
    string S; cin >> S;
    auto res = run_enumerate(S);
    i64 ans = 0;
    for(auto a : res) ans += a.length - a.period * 2 + 1;
    cout << ans << endl;
    return 0;
}




struct ios_do_not_sync {
    ios_do_not_sync() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
    }
} ios_do_not_sync_instance;
accuracy: 1
time_ms: 130
memory_kb: 30296
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
const int INF = 10000000;
vector<int> suffix_array(string S){
  S.push_back(0);
  int N = S.size();
  vector<int> cnt(128, 0);
  for (int i = 0; i < N; i++){
    cnt[S[i]]++;
  }
  for (int i = 0; i < 127; i++){
    cnt[i + 1] += cnt[i];
  }
  vector<int> SA(N), rank(N);
  for (int i = 0; i < N; i++){
    cnt[S[i]]--;
    SA[cnt[S[i]]] = i;
  }
  rank[SA[0]] = 0;
  for (int i = 0; i < N - 1; i++){
    rank[SA[i + 1]] = rank[SA[i]];
    if (S[SA[i]] != S[SA[i + 1]]){
      rank[SA[i + 1]]++;
    }
  }
  int L = 1;
  while (L < N){
    vector<int> SA2(N), rank2(N);
    for (int i = 0; i < N; i++){
      SA2[i] = SA[i] - L;
      if (SA2[i] < 0){
        SA2[i] += N;
      }
    }
    cnt = vector<int>(N, 0);
    for (int i = 0; i < N; i++){
      cnt[rank[SA2[i]]]++;
    }
    for (int i = 0; i < N - 1; i++){
      cnt[i + 1] += cnt[i];
    }
    for (int i = N - 1; i >= 0; i--){
      cnt[rank[SA2[i]]]--;
      SA[cnt[rank[SA2[i]]]] = SA2[i];
    }
    rank2[SA[0]] = 0;
    for (int i = 0; i < N - 1; i++){
      rank2[SA[i + 1]] = rank2[SA[i]];
      if (rank[SA[i]] != rank[SA[i + 1]] || rank[(SA[i] + L) % N] != rank[(SA[i + 1] + L) % N]){
        rank2[SA[i + 1]]++;
      }
    }
    rank = rank2;
    L *= 2;
  }
  SA.erase(SA.begin());
  return SA;
}
vector<int> lcp_array(string &S, vector<int> &SA){
  int N = S.size();
  vector<int> rank(N);
  for (int i = 0; i < N; i++){
    rank[SA[i]] = i;
  }
  vector<int> lcp(N - 1, 0);
  int h = 0;
  for (int i = 0; i < N; i++){
    if (rank[i] > 0){
      int prev = SA[rank[i] - 1];
      if (h > 0){
        h--;
      }
      while (i + h < N && prev + h < N){
        if (S[i + h] != S[prev + h]){
          break;
        }
        h++;
      }
      lcp[rank[i] - 1] = h;
    }
  }
  return lcp;
}
struct segment_tree{
  int N;
  vector<pair<int, int>> ST;
  segment_tree(vector<int> &A){
    int N2 = A.size();
    N = 1;
    while (N < N2){
      N *= 2;
    }
    ST = vector<pair<int, int>>(N * 2 - 1, make_pair(INF, -1));
    for (int i = 0; i < N2; i++){
      ST[N - 1 + i] = make_pair(A[i], i);
    }
    for (int i = N - 2; i >= 0; i--){
      ST[i] = min(ST[i * 2 + 1], ST[i * 2 + 2]);
    }
  }
  pair<int, int> range_min(int L, int R, int i, int l, int r){
    if (r <= L || R <= l){
      return make_pair(INF, -1);
    } else if (L <= l && r <= R){
      return ST[i];
    } else {
      int m = (l + r) / 2;
      return min(range_min(L, R, i * 2 + 1, l, m), range_min(L, R, i * 2 + 2, m, r));
    }
  }
  pair<int, int> range_min(int L, int R){
    return range_min(L, R, 0, 0, N);
  }
};
void dfs(vector<tuple<int, int, int, int>> &query, vector<int> &SA, segment_tree &ST, int L, int R){
  if (R - L == 1){
    return;
  }
  pair<int, int> P = ST.range_min(L, R - 1);
  int mn = P.first;
  int m = P.second + 1;
  if (m - L < R - m){
    for (int i = L; i < m; i++){
      query.push_back(make_tuple(m, R, SA[i] - mn, SA[i] + mn));
    }
  } else {
    for (int i = m; i < R; i++){
      query.push_back(make_tuple(L, m, SA[i] - mn, SA[i] + mn));
    }
  }
  dfs(query, SA, ST, L, m);
  dfs(query, SA, ST, m, R);
}
struct binary_indexed_tree{
  int N;
  vector<int> BIT;
  binary_indexed_tree(int N): N(N), BIT(N + 1, 0){
  }
  void add(int i){
    i++;
    while (i <= N){
      BIT[i]++;
      i += i & -i;
    }
  }
  int sum(int i){
    int ans = 0;
    while (i > 0){
      ans += BIT[i];
      i -= i & -i;
    }
    return ans;
  }
  int sum(int L, int R){
    return sum(R) - sum(L);
  }
};
int main(){
  string S;
  cin >> S;
  int N = S.size();
  vector<int> SA = suffix_array(S);
  vector<int> LCP = lcp_array(S, SA);
  segment_tree ST(LCP);
  vector<tuple<int, int, int, int>> query;
  dfs(query, SA, ST, 0, N);
  int Q = query.size();
  vector<vector<pair<int, int>>> add(N + 1), sub(N + 1);
  for (int i = 0; i < Q; i++){
    int L = get<0>(query[i]);
    int R = get<1>(query[i]);
    int mn = get<2>(query[i]);
    int mx = get<3>(query[i]);
    mn = max(mn, 0);
    mx = min(mx, N - 1);
    sub[mn].push_back(make_pair(L, R));
    add[mx + 1].push_back(make_pair(L, R));
  }
  vector<int> pos(N);
  for (int i = 0; i < N; i++){
    pos[SA[i]] = i;
  }
  binary_indexed_tree BIT(N);
  long long ans2 = 0;
  for (int i = 0; i <= N; i++){
    for (auto P : add[i]){
      ans2 += BIT.sum(P.first, P.second);
    }
    for (auto P : sub[i]){
      ans2 -= BIT.sum(P.first, P.second);
    }
    if (i < N){
      BIT.add(pos[i]);
    }
  }
  cout << ans2 << endl;
}
accuracy: 1
time_ms: 150
memory_kb: 45932
final_rank: 9