Problem:
Score : 200 points

Problem Statement

You are going to take the entrance examination of Kyoto University tomorrow
and have decided to memorize a set of strings S that is expected to appear in the examination.
Since it is really tough to memorize S as it is,
you have decided to memorize a single string T that efficiently contains all the strings in S.

You have already confirmed the following conditions for S and T are satisfied.

Every string in S is a consecutive subsequence(1) in T .

For every pair of strings x, y (x \neq y) in S ,
x is not a subsequence(2) of y.

Note that (1) is ''consecutive subsequence'', while (2) is ''subsequence''.

The next day, you opened the problem booklet at the examination
and found that you can get a full score only if you remember S.
However, You have forgot how to reconstruct S from T .
Since all you remember is that T satisfies the above conditions,
first you have decided to find the maximum possible number of elements in S .

Constraints

1 \leq |T| \leq 10^5

T consists of only lowercase letters.

Partial points

30 points will be awarded for passing the test set satisfying the condition: 1 \leq |T| \leq 50 .

Another 30 points will be awarded for passing the test set satisfying the condition: 1 \leq |T| \leq 10^3.

Input

The input is given from Standard Input in the following format:

T

The input only consists of T on one line.

Output

Print the maximum number of elements inS .

Sample Input 1

abcabc

Sample Output 1

3

In this case, ab，ca and bc are an example of the optimum answers.

Sample Input 2

abracadabra

Sample Output 2

7

Sample Input 3

abcbabbcabbc

Sample Output 3

8

Sample Input 4

bbcacbcbcabbabacccbbcacbaaababbacabaaccbccabcaabba

Sample Output 4

44

Solution in C++14 (GCC 5.4.1) (judge verdict: Time Limit Exceeded)

#include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;
using ld = long double;
const ld eps = 1e-9;
using ll = long long int;
using ha = pair<ll, ll>;
struct RollingHash {
	static const ll mul0 = 10009, mul1 = 10007;
	static const ll add0 = 1000010007, add1 = 1003333331;
	size_t len;
	//vector<ll> hash_, hash2_;
	vector<ha>hash_;
	//static vector<ll> pmo_, pmo2_;
	static vector<ha>pmo_;
	void init(const vector<ll>& s) {
		len = s.size();
		hash_.resize(len + 1);
		hash_[0] = make_pair(0, 0);

		if (pmo_.empty()) {
			pmo_.push_back(make_pair(1, 1));
		}
		while (pmo_.size() <= len) {
			pmo_.push_back(make_pair(pmo_.back().first*mul0, pmo_.back().second*mul1));
		}
		for (unsigned int i = 0; i < len; ++i) {
			hash_[i + 1] = make_pair((hash_[i].first * mul0 + s[i]), (hash_[i].second*mul1 + s[i]));
		}
		return;
	}
	void init(const string& s) {
		vector<ll>v;
		for (char c : s) {
			v.push_back(c);
		}
		init(v);
	}
	ha hash(const int l, const int r)const { // s[l..r]
		return make_pair(hash_[r + 1].first - hash_[l].first * pmo_[r + 1 - l].first,
			hash_[r + 1].second - hash_[l].second * pmo_[r + 1 - l].second);
	}
	ha  hash()const { // s[all]
		return hash(0, len - 1);
	}

	//hashの結合　
	static ha concat(const ha L, const ha R, const int RLength) { // hash(L+R) 
		return make_pair((R.first + L.first*pmo_[RLength].first), (R.second + L.second*pmo_[RLength].second));
	}

	//indexの位置をfromからtoに変えたもののハッシュを返す。
	ha get_changed_hash(const int index, const ll from, const ll to)const {
		const ha p(hash());
		return make_pair(
			p.first + (to - from) * pmo_[len - index - 1].first,
			p.second + (to - from) * pmo_[len - index - 1].second);
	}
};
vector<ha> RollingHash::pmo_;

int getnum(const RollingHash&rh,const int num) {
	unordered_set<long long int>aset1,aset2;
	for (int i = 0; i <= rh.len - num; ++i) {
		aset1.emplace(rh.hash(i, i + num - 1).first);
		aset2.emplace(rh.hash(i, i + num - 1).second);
	}
	return max(aset1.size(),aset2.size());
}

int main() {
	string st; cin >> st;
	RollingHash rh;
	rh.init(st);
	int amin = 1;
	int amax = st.size() + 1;
	while (amin + 2 < amax) {
		int amid1 = (amin * 2 + amax) / 3;
		int amid2 = (amin * 1 + amax * 2) / 3;
		int ans1 = getnum(rh, amid1);
		int ans2 = getnum(rh, amid2);
		if (ans1 < ans2) {
			amin = amid1;

		}
		else {
			amax = amid2;
		}
	}
	int ans = 0;
	for (int i = amin; i < amax; ++i) {
		ans = max(ans, getnum(rh,i));
	}
	cout << ans << endl;
	
	return 0;
}