显然,在遇到两个字符串需按位进行操作的问题时,我们首先会想到将两个字符串按位遍历
  类如:
int dp[][]; //
for(int i=1;i<=a.size();i++)
{
    for(int j=1;j<=b.size();j++)
    {
      if(a[i]==b[i]) {}
            else{}

    }
}
dp[i][j]的i和j分别代表每个字符串遍历到了第几个字母;  

那么,作为一个dp初学者,我们不妨照葫芦画瓢,对本题的s、t字符串进行按位遍历(以下我设a、b)字符串。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
string a,b;
int dp[5005][5005];
int ans=0;
signed main()
{
	cin>>a>>b;
	int len1=a.size();
	int len2=b.size();
以上为我的代码准备;

这个时候,我们进行可以很简单地想出来的第一步!
	for(int i=1;i<=len1;i++)
	{
		for(int j=1;j<=len2;j++)
		{
			if(a[i-1]==b[j-1])
			{
				dp[i][j]=dp[i-1][j-1]+1;
			}
显然,我们可以知道,如果a[i]==b[j],那么ans是会++的;
而我们又知道!dp的特质是新的子问题的解,是由旧的子问题的解得来的!
那么我们很容易就可以得到,dp[i][j]=dp[i-1][j-1];

好的,问题来了,我们知道新解是由旧解得来的,我们又如何确定“旧解”是什么呢?
因为数据范围可以允许进行n^2的复杂度,并且需要遍历两个字符串
并且!我们易知dp[i][j]一般是由dp[i-1][j]/dp[i][j-1]/dp[i-1][j-1]得到的;
所以!易得结果!

//第二步
         else if(a[i-1]!=b[j-1])
			{
				dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
			}
我个人认为比较有难度的是这个。
首先,我们秉持着这个——>dp的本质是继承/选择;
那么当a[i]!=b[j]时,继承什么?又选择什么呢?
继承:
显然我们要从dp[i-1][j]和dp[i][j-1]中继承;
再补一点原因:
(1)因为a[i]!=b[j],所以本质上这一步是没有即时性的操作的;所以一定是要从前面的旧解走的;
(2)显然dp[i-1][j-1]已经用过了,我们可以往dp[i-1][j]和dp[i][j-1]处想;
选择:
(1)显然是选择最大的;
(2)二维和“两个字符串的对称性”;

好的;现在我们就写出了该dp的状态转移方程。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
string a,b;
int dp[5005][5005];
signed main()
{
	while(cin>>a>>b)
	{
	int len1=a.size();
	int len2=b.size();
	dp[0][0]=0;
	if(a[0]==b[0])
	{
		dp[1][1]=1;
	}
	for(int i=1;i<=len1;i++)
	{
		for(int j=1;j<=len2;j++)
		{
			if(a[i-1]==b[j-1])
			{
				dp[i][j]=dp[i-1][j-1]+1;
			}
			else if(a[i-1]!=b[j-1])
			{
				dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
			}
		}
	}
	cout<<dp[len1][len2]<<endl;
    }  
	return 0;
}