#include<bits/stdc++.h>
#include<stdio.h>
using namespace std;
typedef long long int ld;
typedef unsigned long long int lu;
typedef vector< int > vi;
typedef vector < ld > vd;
typedef set <ld> sd;
typedef vector< vi > vvi;
typedef vector< vd > vvd;
typedef pair< int,int > ii;
typedef pair< ld,ld > id;
#define sz(a) ld((a).size())
#define pb push_back
#define all(c) (c).begin(),(c).end()
#define tr(c,i) for(typeof((c).begin() i = (c).begin(); i != (c).end(); i++)
#define present(c,x) ((c).find(x) != (c).end())
#define cpresent(c,x) (find(all(c),x) != (c).end())

#define rep(i,a,b) for(i=a;i<b;i++)
#define REP(i,a,b) for(i=a;i<=b;i++)
#define reprev(i,a,b) for(i=a;i>=b;i--)


#define Vi vector
#define pr pair
#define isnum(a) (a>=48 && a<=57)
#define isS(a) (a>='a' && a<='z')
#define isU(a) (a>='A' && a<='Z')
#define toS(a) (isU(a)?a+32:a)
#define toU(a) (isS(a)?a-32:a)
#define toC(a) a&15

vector<char> prime (10000000+1, true);
void sieve(ld n)
{	
	//O(nloglogn) time
	prime[0] = prime[1] = false;
	for (ld i=2; i<=n; ++i)
		if (prime[i])
			if (i * 1ll * i <= n)
				for (ld j=i*i; j<=n; j+=i)
					prime[j] = false;
}


vd v1;
vector <bool> visit;
vvd g;
vvd g1;
vd ar;
vvd final;
//ld mind = 1000000006;
vd mind;
ld c;

//for topological sort of a graph
void dfs(ld i,ld n)
{
	visit[i] = true;
	ld j,k;
	for(j=0;j<g[i].size();j++)
	{
		if(!visit[g[i][j]])
		{
			dfs(g[i][j],n);
		}
	}
	v1.pb(i);
}
//next step
//from transposed graph g1,get strongly connected components
void dfs1(ld i,ld n,ld len)
{
	visit[i] = true;
	ld j,k;
	final[len].pb(i);
	mind[len] = min(mind[len],ar[i]);
	rep(j,0,g1[i].size())
	{
		if(!visit[g1[i][j]])
		{
			dfs1(g1[i][j],n,len);
		}
	}
}

vvd dp;

/*int main(){
	ld N,i,j,k;
	ld W;
	cin >> N >> W;
	ld w[N],v[N];
	ld sum=0;
	rep(i,0,N)
	{
		cin >> w[i] >> v[i];
		sum+=v[i];
	}
	dp = vvd(N+1,vd(sum+1,1000000000));
	dp[0][0]=0;
	REP(i,1,N)
	{
		dp[i][0]=0;
	}
	REP(i,1,N)
	{
		REP(j,1,sum)
		{
			if(j<v[i-1])dp[i][j] = dp[i-1][j];
			else dp[i][j] = min(dp[i-1][j],w[i-1]+dp[i-1][j-v[i-1]]);
		}
	}
	ld maxs=0;
	reprev(i,sum,0)
	{
		if(dp[N][i]<=W)
		{
			maxs = i;
			break;
		}
		//cout << endl;
	}
	cout << maxs << endl;
	return 0;
}*/
void lcs( string X, string Y, ld m, ld n ) 
{ 
   ld L[m+1][n+1]; 
  
   /* Following steps build L[m+1][n+1] in bottom up fashion. Note 
      that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1] */
   for (ld i=0; i<=m; i++) 
   { 
     for (ld j=0; j<=n; j++) 
     { 
       if (i == 0 || j == 0) 
         L[i][j] = 0; 
       else if (X[i-1] == Y[j-1]) 
         L[i][j] = L[i-1][j-1] + 1; 
       else
         L[i][j] = max(L[i-1][j], L[i][j-1]); 
     } 
   } 
  
   // Following code is used to print LCS 
   ld index = L[m][n]; 
  
   // Create a character array to store the lcs string 
   char lcs[index+1]; 
   lcs[index] = '\0'; // Set the terminating character 
  
   // Start from the right-most-bottom-most corner and 
   // one by one store characters in lcs[] 
   ld i = m, j = n; 
   while (i > 0 && j > 0) 
   { 
      // If current character in X[] and Y are same, then 
      // current character is part of LCS 
      if (X[i-1] == Y[j-1]) 
      { 
          lcs[index-1] = X[i-1]; // Put current character in result 
          i--; j--; index--;     // reduce values of i, j and index 
      } 
  
      // If not same, then find the larger of two and 
      // go in the direction of larger value 
      else if (L[i-1][j] < L[i][j-1]) 
         j--; 
      else
         i--; 
   } 
  
   // Print the lcs 
   cout << lcs << endl; 
} 
  
/* Driver program to test above function */
int main() 
{ 
  string s,t;
  cin >> s;
  cin >> t;
  int m = s.size();
  int n = t.size(); 
  lcs(s, t, m, n); 
  return 0; 
} 	

Measured memory_bytes: 80384