G
N
I
D
A
O
L

线性DP——子序列问题浅谈

很多人都不理解为什么可以用 f i 表示一个最长上升子序列大小?

那么我们可以看一下这个“上升”二字这才是这种类型问题的重点——上升要求的是什么?

不就是单调递增,即后一个比前一个大,所以只需要求这个序列的最后一个数的下标就行了。

类比的,这道题https://www.luogu.com.cn/problem/P4933

简化题目:

在给定的序列中找不同的等差数列(可以不连续)

那么我们只需要记什么?

公差——在最长上升子序列中我们本来要求记下来最后一个数,但是我们拥有了当前下标i,所以不需要记

而这道题:

对于两个数字,他们组成的等差数列的公差一定是一样的

那么我们不必去枚举公差,直接枚举第 个数前面那个数,得到公差进行转移即可

用 f[i][j]表示以 结尾公差为 的等差数列个数

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e3+10;
const int T=20010;
const int M=998244353;
long long f[N][T+T+30],h[N];
int n;
long long ans;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%lld",&h[i]);
    for(int i=1;i<=n;i++){
        ans=(ans+1)%M;
        for(int j=i-1;j>=1;j--){
            f[i][h[i]-h[j]+T]=(f[i][h[i]-h[j]+T]+1+f[j][h[i]-h[j]+T])%M;
            ans=(f[j][h[i]-h[j]+T]+ans+1)%M;
        }
    }
    cout<<ans;
}

 总结:线性DP绝大部分都是要找最优子结构的,在贪心里也是同样的,但是我们对于“模板化”的东西不能太迷恋,这也是线性dp的魅力,DP先用一个数组来描述问题答案,在去求解!

posted @ 2022-01-26 17:16  中指半仙  阅读(66)  评论(0编辑  收藏  举报