/*
--------------------------------DO NOT COPY I REQUEST YOU PLEASE--------------------------
AUTHOR : Chandan Agrawal
College : Poornima College of Engg. jaipur, Raj
Mail : chandanagrawal23@gmail.com
*/
#include<bits/stdc++.h>
#include<stdio.h>
using namespace std;
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define MAX 100050
#define ll long long
#define ld long double
#define lli long long int
#define pb emplace_back
#define INF 1000000000
#define mod 1000000007
#define MOD 1000000007
// trignometric function always give value in Radians only
#define PI acos(-1) //3.1415926535897932384626433832795028
#define dsin(degree) sin(degree*(PI/180.0))
#define dcos(degree) cos(degree*(PI/180.0))
#define dtan(degree) tan(degree*(PI/180.0))
#define rsin(radian) sin(radian)
#define rcos(radian) cos(radian)
#define rtan(radian) tan(radian)
#define loop(i,n) for (lli i = 0; i < n; i++)
#define loopitr(xt,vec) for (auto xt : vec)
#define FOR(i,a,b) for (lli i = a; i < b; i+=1)
#define loop_rev(i,n) for (lli i = n-1; i >= 0; i--)
#define FOR_REV(i,a,b) for (lli i = a; i >= b; i--)
#define itr :: iterator it
#define WL(t) while(t --)
#define all(v) v.begin(),v.end()
#define makeuniq(v) v.resize(unique(all(v)) - v.begin()); //only uniq element in vector after this
#define sz(x) int(x.size())
#define F first
#define S second
#define mii map<lli,lli>
#define vi vector<lli>
#define seti set<lli>
#define pii pair<lli,lli>
#define gcd(a,b) __gcd((a),(b))
#define lcm(a,b) (a/gcd(a,b))*b
#define abs(x) ((x < 0)?-(x):x)
template <typename T>
void print(T x){cout<<x<<endl;}
template <typename T1, typename T2>
void print2(T1 x,T2 y){cout<<x<<" "<<y<<endl;}
template <typename T1, typename T2,typename T3>
void print3(T1 x, T2 y,T3 z){cout<<x<<" "<<y<<" "<<z<<endl;}
#define scanarr(a,n) for(lli i=0;i<n;i++) cin>>a[i];
#define scanvector(a,n) for(lli i=0;i<n;i++){ lli x ; cin>>x; a.push_back(x);}
#define printarr(a,n) for(lli i=0;i<n;i++) cout<<a[i]<<" "; cout<<endl;
#define printvector(vec) for(auto xt : vec) cout<<xt<<" "; cout<<"\n";
#define printset(st) for(auto xt : st) cout<<xt<<" "; cout<<"\n";
#define FD(N) fixed<<setprecision(N)
#define endl '\n'
#define deb(x) cout<<#x<<" "<<x<<endl;
/*
ifstream cinn("i3.txt");
ofstream coutt("o3.txt");
*/
bool isvowel(char v) { return (0x208222>>(v&0x1f))&1; }
lli mceil(lli a,lli b){
if(a%b==0) return(a/b);
else return(a/b +1);
}
lli mfloor(lli a,lli b){
return(a/b);
}
ll modmul(ll a, ll b) {
return ((a%mod) * (b%mod)) % mod;
}
ll modadd(ll a , ll b){
return((a%mod)+(b%mod)+mod)%mod;
}
ll modsub(ll a , ll b){
return((a%mod) - (b%mod) + mod)%mod;
}
lli fastexpo(lli a,lli b){
a = a%mod;
lli ans=1;
while(b){
if(b&1)
ans=(ans*1ll*a)%mod;
a=(a*1ll*a)%mod;
b=b/2;
}
return ans;
}
/* -----------------------------------------------------HASHING-------------------------------------------------------------------*/
/*
some key points -
1. Use (long int) to remove TLE or Memory Limit issue
2. If still Wrong answer then may be collision occur , use p as bigger prime no. p : [31,53,107,209,4793]
3. use mod either 1e9+7
4 .If it still shows WA then surely collision occurs use Double Hashing
Double Hashing -
Make Prehash Array using two different p and mod so chances of collision is less
5. use pass by reference always
*/
#define maxlen 100005 //maximum length of string
lli pow_p1[maxlen];
lli p_inv1[maxlen];
lli pow_p2[maxlen];
lli p_inv2[maxlen];
void init(lli p1, lli p2)
{
pow_p1[0] = p_inv1[0] = pow_p2[0] = p_inv2[0] = 1;
lli pinv1 = fastexpo(p1,mod-2);
lli pinv2 = fastexpo(p2,mod-2);
for(lli i=1;i<maxlen;i++)
{
pow_p1[i] = modmul(pow_p1[i-1],p1);
p_inv1[i] = modmul(p_inv1[i-1],pinv1);
pow_p2[i] = modmul(pow_p2[i-1],p2);
p_inv2[i] = modmul(p_inv2[i-1],pinv2);
}
}
struct Hash{
// 0 based indexing
lli prehash1[maxlen];
lli prehash2[maxlen];
// hash(s) = sigma(i=0 to n-1) s[i]*p^(i)
// a->1 , b->2 , c->3 and so on
void precomputehash(vi &s){ //p can be any prime 19 , 31, 53,107 ...
prehash2[0] = prehash1[0] = (s[0]+1);
for (lli i=1;i<s.size();i++) {
prehash1[i]= modadd(prehash1[i-1] , modmul((s[i]+1),pow_p1[i]));
prehash2[i]= modadd(prehash2[i-1] , modmul((s[i]+1),pow_p2[i]));
}
}
// hash[l..r] = ((hash[upto r] - hash[upto (l-1)] ) / P^l) % mod = ((hash[upto r] - hash[upto (l-1)] ) * modinv(P^l) )%mod
pii gethash(lli l, lli r){
if(l==0)
return(make_pair( (prehash1[r]%mod) , (prehash2[r]%mod) ) );
else{
lli ans1 = modsub(prehash1[r],prehash1[l-1]);
ans1 = modmul(ans1, p_inv1[l]);
lli ans2 = modsub(prehash2[r],prehash2[l-1]);
ans2 = modmul(ans2, p_inv2[l]);
return (make_pair(ans1,ans2));
}
}
// hash value of all string means hash[0..(n-1)] // 0 based indexing
pii totalhash(vi &s){
return(make_pair(prehash1[sz(s)-1]%mod , prehash2[sz(s)-1]%mod));
}
};
bool check(Hash *obj , vector<vi> paths , lli n , lli mid)
{
map<pair<lli ,lli>,lli>mp;
set<pair<lli,lli>>st1;
for(int j=0;j<=sz(paths[0])-mid;j+=1)
{
st1.insert(obj[0].gethash(j,j+mid-1));
}
for(auto xt : st1)
mp[xt]++;
for(int i=1;i<n;i++)
{
set<pair<lli,lli>>st;
for(int j=0;j<=sz(paths[i])-mid;j+=1)
{
st.insert(obj[i].gethash(j,j+mid-1));
}
for(auto xt : st)
{
if(st1.find(xt)!=st1.end())
{
mp[xt]++;
}
}
}
for(auto xt : mp)
{
if(xt.S==n)
return true;
}
return false;
}
class Solution {
public:
int longestCommonSubpath(int nn, vector<vector<int>>& path) {
init(53,4793);
lli n = path.size();
vector<vi>paths;
for(auto xt : path)
{
vi tmp;
for(auto xr : xt)
{
tmp.pb(1LL*xr);
}
paths.pb(tmp);
}
Hash obj[n];
lli mini = INF;
for(int i=0;i<n;i++){
obj[i].precomputehash(paths[i]);
if(mini >sz(paths[i]))
mini = sz(paths[i]);
}
lli l=1 , r = mini , ans = 0;
while(l<=r)
{
lli mid = (l+r)/2;
if(check(obj , paths , n , mid))
{
ans = mid;
l = mid+1;
}
else
r=mid-1;
}
return ans;
}
};