// Standard Stuff
#include <bits/stdc++.h>
using namespace std;

// Macros
#define F      first
#define S      second
#define PB     push_back
#define MP     make_pair
#define ALL(c) c.begin(),c.end()

// Rename Datatypes
using ll  = long long;
using ld  = long double;
using pii = std::pair <int,int>;

// Random
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
/* [a,b] */ template<class T> T rnd_IntType(T a, T b){ return uniform_int_distribution<T>(a, b)(rng); }
/* [a,b) */ template<class T> T rnd_RealType(T a, T b){ return uniform_real_distribution<T>(a,b)(rng); }

// Common Functions
ll fastpow(ll a, ll ex){ ll res = 1; while(ex){ if(ex & 1) res *= a; a *= a; ex >>= 1; } return res; }
ll fastpow(ll a, ll ex, ll m){ a %= m; ll res = 1; while(ex){ if(ex & 1) res = (a*res) % m; a = (a*a) % m; ex >>= 1; } return res; }
ll modinverse(ll a, ll m){ ll m0 = m; ll y = 0, x = 1; while (a > 1){ ll q = a / m; a %= m; swap(a,m); x -= q*y; swap(x,y); } if(x < 0) x += m0; return x; }

// Output, Common Containers
template <typename T> ostream& operator << (ostream &os, const set<T> &v) { for (T i : v) os << i << ' '; return os; }
template <typename T> ostream& operator << (ostream &os, const vector<T> &v) { for (T i : v) os << i << ' '; return os; }
template <typename T> ostream& operator << (ostream &os, const deque<T> &v) { for (T i : v) os << i << ' '; return os; }
template <typename T, typename S> ostream& operator << (ostream &os, const pair<T, S> &v) { os << "(" << v.F << "=>" << v.S << ") "; return os; }
template <typename T, typename S> ostream& operator << (ostream &os, const map<T, S> &v) { for (auto i : v) os << i << ' '; return os; }

// Debugging
#ifdef LOCAL
	#define trace(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); d__f(_it, args); }
	void d__f(istream_iterator<string> it) {}
	template<typename Head, typename... Tail> void d__f(istream_iterator<string> it, Head H, Tail... T) { cerr << *it << " <=> [" << H << "]\n"; d__f(++it, T...); }
#else
	#define trace(args...)
#endif


// CODE STARTS HERE

const int modulo1 = 1e9+7;
const int modulo2 = 998244353;

const int mod = 1e9+7;

ll add(ll a, ll b) { return (a + b) % mod; }
ll sub(ll a, ll b) { return (a - b) % mod; }
ll mul(ll a, ll b) { return (a * b) % mod; }

signed main() {
	std::ios::sync_with_stdio(false); //Warning: Do NOT use C I/O now.
	std::cin.tie(nullptr); //Note: Comment out this line for interactive questions.
	// std::cout.setf(std::ios::fixed); std::cout.precision(20); //Note: To output decimals correctly.

	// int t; cin>>t;
	// for(int test_no = 1; test_no <= t; ++test_no){}

	string s,t;
	cin>>s>>t;

	vector<vector<pair<int,pii>>> dp(s.size()+1, vector<pair<int,pii>>(t.size()+1));

	for(int i=0; i<=s.size(); ++i) dp[i][0] = {0,{0,0}};
	for(int i=0; i<=t.size(); ++i) dp[0][i] = {0,{0,0}};

	for(int i=1; i<=s.size(); ++i){
		for(int j=1; j<=t.size(); ++j){
			dp[i][j] = { dp[i-1][j].F, {i-1,j} };

			if(dp[i][j-1].F > dp[i][j].F)
				dp[i][j] = { dp[i][j-1].F, {i,j-1} };

			int c = (s[i-1]==t[j-1]) ? 1 : 0;
			if(dp[i-1][j-1].F + c > dp[i][j].F)
				dp[i][j] = { dp[i][j-1].F + c, {i-1,j-1} };
		}
	}

	// trace(dp[s.size()][t.size()].F);

	string ans = "";
	pii ptr = {s.size(), t.size()};
	while(ptr.F|ptr.S != 0){
		pii nptr = dp[ptr.F][ptr.S].S;
		if(nptr.F == ptr.F-1 and nptr.S == ptr.S-1 and s[ptr.F-1]==t[ptr.S-1])
			ans = s[ptr.F-1] + ans;
		ptr = nptr;
	}

	cout<<ans;
}

Measured memory_bytes: 105984