DP-线性DP的一些题目

1.最长上升子序列

活动 - AcWing

给定一个长度为n的数列,求数值严格单调递增的子序列的长度最长是多少。

解题

我们将上升子序列的倒数第二个数作为状态划分的依据,当其小于当前数时,长度可以+1,否则不行。

#include
using namespace std;
const int N=1010;
int n,a[N],f[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        f[i]=1;
        for(int j=1;j<=i;j++)
        {
            if(a[j]

有一个O(nlogn)的做法,使用二分来优化。

在此前,每次进行状态转移时,我们需要遍历一遍所有可能的倒数第二个数,才能找出方案,但是其实,我们可以用一个数组存储每个长度的上升子序列末尾最小的值。我们可以很容易地知道,这个数组一定是单调递增的,因为当上升子序列的长度相同时,末尾最小的上升子序列,一定是我们最优的选择,如果当前上升子序列的长能够+1,则说明当前长度n+1的上升子序列末尾元素一定比上一个长度n的末尾元素大。

有了这个单调递增的性质,我们进行状态转移的时候,可以通过二分在数组中找出比当前值小的最大元素,把它作为上一个状态,从而进行状态转移。

#include
using namespace std;
const int N=1010;
int a[N],q[N],n;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int len=0;
    q[0]=-2e9;
    for(int i=1;i<=n;i++)
    {
        int l=0,r=len;
        while(l>1;
            if(q[mid]

你可能感兴趣的:(算法,动态规划,c++)