#include <stdio.h>
#include <string>
#include <vector>
#include <random>
#include <chrono>
#include <array>
#include <iostream>
#include <algorithm>
typedef unsigned long long ull;
int gen_base(int before, int after) {
auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
std::mt19937 gen(seed ^ ull(new ull));
std::uniform_int_distribution<int> dist(before+2, after-1);
int base = dist(gen);
return base % 2 == 0 ? base - 1 : base;
}
struct HashTable {
static const int mod = 2000177; // 2000177, 3000077, 4000277
const int step;
std::array<ull, mod> data;
inline int get_hash(ull value) const {
return int((value + step) % mod);
}
HashTable() : step(gen_base(mod / 10, mod)) {
for (auto& it : data) it = 0;
}
void insert(ull value) {
int hash = get_hash(value);
while (true) {
if (data[hash] == value) {
return;
}
if (data[hash] == 0) {
data[hash] = value;
return;
}
hash += step;
if (hash >= mod) {
hash -= mod;
}
}
}
bool search(ull value) const {
int hash = get_hash(value);
while (true) {
if (data[hash] == value) {
return true;
}
if (data[hash] == 0) {
break;
}
hash += step;
if (hash >= mod) {
hash -= mod;
}
}
return false;
}
};
struct PolyHash {
// -------- Static variables --------
static const ull mod = (ull(1) << 61) - 1; // prime mod of hashing
static int base; // odd base of hashing
static std::vector<ull> pow; // powers of base modulo mod;
// -------- Static functions --------
static inline ull add(ull a, ull b) {
// Calculate (a + b) % mod, 0 <= a < mod, 0 <= b < mod
return (a += b) < mod ? a : a - mod;
}
static inline ull sub(ull a, ull b) {
// Calculate (a - b) % mod, 0 <= a < mod, 0 <= b < mod
return (a -= b) < mod ? a : a + mod;
}
static inline ull mul(ull a, ull b){
// Calculate (a * b) % mod, 0 <= a < mod, 0 <= b < mod
ull l1 = (uint32_t)a, h1 = a >> 32, l2 = (uint32_t)b, h2 = b >> 32;
ull l = l1*l2, m = l1*h2 + l2*h1, h = h1*h2;
ull ret = (l & mod) + (l >> 61) + (h << 3) + (m >> 29) + (m << 35 >> 3) + 1;
ret = (ret & mod) + (ret >> 61);
ret = (ret & mod) + (ret >> 61);
return ret-1;
}
// -------- Variables of class --------
std::vector<ull> pref; // polynomial hash on prefix
// Constructor from string:
PolyHash(const std::string& s)
: pref(s.size()+1u, 0)
{
// Pre-calculate powers of base:
while (pow.size() <= s.size()) {
pow.push_back(mul(pow.back(), base));
}
// Calculate polinomial hash on prefix:
for (int i = 0; i < (int)s.size(); ++i) {
pref[i+1] = add(mul(pref[i], base), s[i]);
}
}
// Get hash from [pos, pos+len-1] segment of string
inline ull operator()(const int pos, const int len) const {
return sub(pref[pos+len], mul(pref[pos], pow[len]));
}
};
// Init static variables of class PolyHash:
int PolyHash::base((int)1e9+7);
std::vector<ull> PolyHash::pow{1};
// Solve problem using binary search and hash table in O(n log(n)):
int solve(const std::string& s, const std::string& t) {
// Pre-calculate hash:
PolyHash hash_s(s), hash_t(t);
// Binary search by len:
int low = 0, high = std::min((int)s.size(), (int)t.size())+1;
while (high - low > 1) {
int mid = (low + high) / 2;
// Insert all hashes of segments length mid of string s:
HashTable hashes;
for (int i = 0; i + mid - 1 < (int)s.size(); ++i) {
hashes.insert(hash_s(i, mid));
}
// Search all hashes of segments length mid of string t:
bool success = false;
for (int i = 0; i + mid - 1 < (int)t.size(); ++i) {
if (hashes.search(hash_t(i, mid))) {
success = true;
break;
}
}
if (success) low = mid; else high = mid;
}
return low;
}
void input(std::string& a, std::string& b) {
char buf[1+1000000];
scanf("%1000000s", buf);
a = buf;
scanf("%1000000s", buf);
b = buf;
}
void gen(const int n, std::string& s, std::string& t) {
// Generate test length n and answer n / 2
s.assign(n, 'v');
t.assign(n, 'v');
for (int i = 0, j = n-1; i <= j; ++i, --j) {
s[i] = '~';
t[j] = '-';
}
}
int main() {
// Generate random base:
PolyHash::base = gen_base(256, 2e9);
std::string s, t;
input(s, t);
std::cout << solve(s,t);
return 0;
}