/*
Problem "Ada and Terramorphing" on spoj.com
Solution: polynomial hash, sort, binary search, O(n log(n)^2)
*/
#include <stdio.h>
#include <cassert>
#include <algorithm>
#include <vector>
#include <random>
#include <chrono>
#include <string>
#include <iostream>
typedef unsigned long long ull;
// Generate random base in (before, after) open interval:
int gen_base(const int before, const int after) {
auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
std::mt19937 mt_rand(seed);
int base = std::uniform_int_distribution<int>(before+2, after-1)(mt_rand);
return base % 2 == 0 ? base-1 : base;
}
struct PolyHash {
// -------- Static variables --------
static const ull mod = (1ull << 61) - 1; // prime mod of polynomial hashing
static std::vector<ull> pow; // powers of base modulo mod
static int base; // base (point of hashing)
// --------- Static functons --------
static inline ull sub(ull a, ull b) {
// Sub `b` from `a` modulo mod (0 <= a < mod, 0 <= b < mod)
return (a -= b) < 0 ? a + mod : a;
}
static inline ull add(ull a, ull b) {
// Add `b` to `a` modulo mod (0 <= a < mod, 0 <= b < mod)
return (a += b) < mod ? a : a - mod;
}
static inline ull mul(ull a, ull b) {
// Mul `a` and `b` modulo 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; // Hash on prefix modulo mod
// Cunstructor from string:
PolyHash(const std::string& s)
: pref(s.size()+1u, 0)
{
const int n = s.size(); // Firstly calculated needed power of base:
while ((int)pow.size() <= n) {
pow.push_back(mul(pow.back(), base));
}
for (int i = 0; i < n; ++i) { // Fill arrays with polynomial hashes on prefix
pref[i+1] = add(mul(pref[i], base), s[i]);
}
}
// Polynomial hash of subsequence [pos, pos+len)
inline ull operator()(const int pos, const int len) const {
return sub(pref[pos+len], mul(pow[len], pref[pos]));
}
};
// Init static variables of PolyHash class:
int PolyHash::base((int)1e9+7);
std::vector<ull> PolyHash::pow{1};
void gen(int n, std::string& s, std::string& t) {
s.assign(n, '?');
t.assign(n, '?');
for (int i = 0, j = n-1; i <= j; ++i, --j) {
t[j] = s[i] = 'v';
}
for (int i = 0; i < n; ++i) {
s[i] = s[i] == '?' ? '~' : s[i];
t[i] = t[i] == '?' ? '-' : t[i];
}
}
void input(std::string& s, std::string& t) {
char buf[1+1000000];
scanf("%1000000s", buf);
s = buf;
scanf("%1000000s", buf);
t = buf;
}
int main() {
std::string a, b;
//input(a,b);
gen(10000, a, b);
std::cerr << "generated!" << std::endl;
// Gen random base of hashing:
PolyHash::base = gen_base(256, 2e9);
// Create hashing objects from strings:
PolyHash hash_a(a), hash_b(b);
// Binary search by length of same subsequence:
int pos = -1, low = 0, high = (int)std::min(a.size(), b.size())+1;
while (high - low > 1) {
//std::cout << "low = " << low << " high = " << high << std::endl;
int mid = (low + high) / 2;
std::vector<ull> hashes;
for (int i = 0; i + mid - 1 < (int)a.size(); ++i) {
hashes.push_back(hash_a(i,mid));
}
std::sort(hashes.begin(), hashes.end());
int p = -1;
for (int i = 0; i + mid - 1 < (int)b.size(); ++i) {
if (std::binary_search(hashes.begin(), hashes.end(), hash_b(i, mid))) {
p = i;
break;
}
}
if (p >= 0) {
low = mid;
pos = p;
} else {
high = mid;
}
}
assert(pos >= 0);
// Output answer:
printf("%d", low);
return 0;
}