#include #include #include #include #include #include #include using namespace std; typedef long long ll; typedef pair pli; void count_sort(vector &b, int bits) { // (optional) //this is just 3 times faster than stl sort for N=10^6 int mask = (1 << bits) - 1; for(int it = 0; it < 2; it++) { int move = it * bits; vector q(1 << bits), w(q.size() + 1); for(int i = 0; i < (int)b.size(); i++) q[(b[i].first >> move) & mask]++; partial_sum(q.begin(), q.end(), w.begin() + 1); vector res(b.size()); for(int i = 0; i < (int)b.size(); i++) res[w[(b[i].first >> move) & mask]++] = b[i]; swap(b, res); } } struct SuffixArray { vector a; string s; SuffixArray(const string& _s) : s(_s + '\0') { int N = s.size(); vector b(N); a.resize(N); for(int i = 0; i < N; i++) { b[i].first = s[i]; b[i].second = i; } int q = 8; while ((1 << q) < N) q++; for (int moc = 0;; moc++) { count_sort(b, q); // sort(all(b)) can be used as well a[b[0].second] = 0; for(int i = 1; i < N; i++) a[b[i].second] = a[b[i - 1].second] + (b[i - 1].first != b[i].first); if ((1 << moc) >= N) break; for(int i = 0; i < N; i++) { b[i].first = (ll)a[i] << q; if (i + (1 << moc) < N) b[i].first += a[i + (1 << moc)]; b[i].second = i; } } for(int i = 0; i < (int)a.size(); i++) a[i] = b[i].second; } vector lcp() { // longest common prefixes: res[i] = lcp(a[i], a[i-1]) int n = a.size(), h = 0; vector inv(n), res(n); for(int i = 0; i < n; i++) inv[a[i]] = i; for(int i = 0; i < n; i++) if (inv[i] > 0) { int p0 = a[inv[i] - 1]; while (s[i + h] == s[p0 + h]) h++; res[inv[i]] = h; if(h > 0) h--; } return res; } }; const int SZ = 1 << 20; int tree[2 * SZ]; void upd(int idx, int val) { idx += SZ; tree[idx] = val; while(idx > 1) { idx /= 2; tree[idx] = min(tree[2*idx], tree[2*idx+1]); } } int qry(int lhs, int rhs) { if(lhs > rhs) return 0; lhs += SZ; rhs += SZ; int ret = 1e9; while(lhs <= rhs) { if(lhs%2) ret = min(ret, tree[lhs++]); if(rhs%2==0) ret = min(ret, tree[rhs--]); lhs /= 2; rhs /= 2; } return ret; } int dp[1000005]; int bestlcp[1000005]; vector> edges[1000005]; int main() { string s; getline(cin, s); int n = s.size(); if(n <= 4) { cout << n << "\n"; return 0; } SuffixArray sa(s); vector arrayv = sa.a; vector lcpv = sa.lcp(); for(int i = 0; i < (int)lcpv.size(); i++) upd(i, lcpv[i]); // left to right stack st; for(int i = 0; i < (int)arrayv.size(); i++) { while(st.size() && arrayv[st.top()] > arrayv[i]) st.pop(); if(st.size()) { int curr = st.top(); bestlcp[arrayv[i]] = max(bestlcp[arrayv[i]], qry(curr+1, i)); } st.push(i); } while(st.size()) st.pop(); // right to left for(int i = (int)arrayv.size()-1; i >= 0; i--) { while(st.size() && arrayv[st.top()] > arrayv[i]) st.pop(); if(st.size()) { int curr = st.top(); bestlcp[arrayv[i]] = max(bestlcp[arrayv[i]], qry(i+1, curr)); } st.push(i); } for(int i = 0; i <= n; i++) { if(i) dp[i] = max(dp[i], dp[i-1]); dp[i + bestlcp[i]] = max(dp[i + bestlcp[i]], dp[i] + bestlcp[i]-3); } cout << n - dp[s.size()] << "\n"; }