for (int i = s.size()-1; i>=0 ; i--)
{
for (int j = i+1; j <s.size(); j++)
{
if (s[i] == s[j])
{
dp[i][j] = dp[i + 1][j - 1] + 2;
ans = max(dp[i][j], ans);
}
else
{
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
如代码所示,这是一段求最长回文串的代码(注意最长回文串在原串中不一定是连续的)
通过这道题,我明白了以下几点
- dp问题一定要确保状态转移方程中等号右边的状态之前已经被更新了,这一点可以帮助我们确定for循环是正序还是逆序.
洛谷红名大佬的dp心得
1. 定义状态。
2. 写出状态转移式。
3. 根据状态转移式找出递推顺序。
4. 处理递推的边界。
5. 找出结果
做完洛谷提单相似基因问题的感悟
转移式通常只考虑最后一点
例如 线性dp中,如果只有一个序列,就靠当前序列i与i-1
如果有两个序列,就考虑a[i]和bj的关系有哪几种情况.
把情况列完一般状态转移方程就出来了;
区间dp:给定若干个闭区间,求最少多少个闭区间能够刚好囊括所有给出的闭区间
解法1:顶尖思路,
cnt表示走到这个点为止,与右区间抵消后的左区间还剩多少,如果是0,那么抵消之前是0,那么一定是答案区间的左端点,如果抵消之后是0,那么是右端点
for (int i = 1; i <= n; i++)
{
int a, b;
cin >> a >> b;
x[a]++, b[y]++;
}
int cnt = 0;
for (int i = 1; i <= 1e6; i++)
{
if (!cnt && x[i]) cout << i<<" ";
cnt += x[i] - y[i];
if (!cnt && y[i]) cout << i << endl;
}
解法二:合并区间,当需要开新区间时,就输出之前的begin和end
struct node //结构体存区间
{
int lo,hi;
}a[50000+10];
bool cmp(node a,node b) //排序
{
return a.lo<b.lo;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].lo>>a[i].hi;
sort(a+1,a+n+1,cmp);
st=a[1].lo;
ov=a[1].hi; //答案区间初始化
for(int i=2;i<=n;i++)
{
if(a[i].lo>ov) //开新区间
{
cout<<st<<" "<<ov<<endl;
st=a[i].lo;
ov=max(ov,a[i].hi);
}
else ov=max(ov,a[i].hi); //扩展原有区间
if(i==n) cout<<st<<" "<<ov<<endl; //注意点3
}
return 0;
}