using System;
using System.Collections.Generic;
class ComputeHash
{
private List<long> hash;
private List<long> invMod;
private long mod;
private long p;
// Constructor to initialize hash values for the given string
public ComputeHash(string s, long p, long mod)
{
int n = s.Length;
this.hash = new List<long>(n);
this.invMod = new List<long>(n);
this.mod = mod;
this.p = p;
long pPow = 1;
long hashValue = 0;
for (int i = 0; i < n; i++)
{
char c = s[i];
// Convert character to numeric value
c = (char)(c - 'A' + 1);
hashValue = (hashValue + c * pPow) % this.mod;
this.hash.Add(hashValue);
// Compute modular inverse
this.invMod.Add(ModularInverse(pPow, this.mod));
pPow = (pPow * this.p) % this.mod;
}
}
// Helper function to compute modular inverse using extended Euclidean algorithm
private long ModularInverse(long a, long m)
{
long m0 = m, t, q;
long x0 = 0, x1 = 1;
if (m == 1)
return 0;
while (a > 1)
{
q = a / m;
t = m;
m = a % m;
a = t;
t = x0;
x0 = x1 - q * x0;
x1 = t;
}
if (x1 < 0)
x1 += m0;
return x1;
}
// Function to get hash value for a substring [l, r]
public long GetHash(int l, int r)
{
if (l == 0)
{
return this.hash[r];
}
long window = (this.hash[r] - this.hash[l - 1] + this.mod) % this.mod;
return (window * this.invMod[l]) % this.mod;
}
}
class LongestCommonSubstring
{
// Function to check if a common substring of length k exists
private static bool Exists(int k, string X, string Y,
ComputeHash hashX1, ComputeHash hashX2,
ComputeHash hashY1, ComputeHash hashY2)
{
for (int i = 0; i <= X.Length - k; i++)
{
for (int j = 0; j <= Y.Length - k; j++)
{
if (X.Substring(i, k) == Y.Substring(j, k))
{
return true;
}
}
}
return false;
}
// Function to find the length of the longest common substring of X and Y
private static int LongestCommonSubstr(string X, string Y)
{
int n = X.Length;
int m = Y.Length;
long p1 = 31;
long p2 = 37;
long m1 = (long)Math.Pow(10, 9) + 9;
long m2 = (long)Math.Pow(10, 9) + 7;
// Initialize two hash objects with different p1, p2, m1, m2 to reduce collision
ComputeHash hashX1 = new ComputeHash(X, p1, m1);
ComputeHash hashX2 = new ComputeHash(X, p2, m2);
ComputeHash hashY1 = new ComputeHash(Y, p1, m1);
ComputeHash hashY2 = new ComputeHash(Y, p2, m2);
// Binary search to find the length of the longest common substring
int low = 0, high = Math.Min(n, m);
int answer = 0;
while (low <= high)
{
int mid = (low + high) / 2;
if (Exists(mid, X, Y, hashX1, hashX2, hashY1, hashY2))
{
answer = mid;
low = mid + 1;
}
else
{
high = mid - 1;
}
}
return answer;
}
static void Main()
{
string X = "GeeksforGeeks";
string Y = "GeeksQuiz";
Console.WriteLine(LongestCommonSubstr(X, Y));
// Output: 5
}
}