首页 > 其他分享 >P4728 [HNOI2009] 双递增序列

P4728 [HNOI2009] 双递增序列

时间:2024-12-06 12:11:12浏览次数:9  
标签:int 递增 len P4728 序列 HNOI2009

P4728 [HNOI2009] 双递增序列

题意简述:

给我们一个序列问我们是否可以将其划分为两个单调递增的子序列

Solution:

无比神奇的状态设计:记 \(f[i][j]\) 表示考虑到 \(i\) 且将 \(a _i\) 放在 \(U\) ,\(U\) 的长度为 \(j\) 时,\(V\) 的末尾的最小值

那么我们就可以得到转移:

当 \(a_i<a_{i+1}\) 时,可以将 \(a_{i+1}\) 拼到 \(a_i\) 之后:
\(U: ........a_ia_{i+1}\)
\(V: ......f[i][len_u]\)
\(f[i+1][len_u+1]=\min{f[i+1][len_u+1],f[i][len_u]}\)

同理,当 \(f[i][len_u]<a_{i+1}\) 时,可以将 \(a_{i+1}\) 拼到 \(f\) 之后:
\(U: .....................a_i\)
\(V: ......f[i][len_u]a_{i+1}\)
\(f[i+1][len_v+1]=\min{f[i+1][len_v+1],a_i}\)

注意:本文只是使用 \(U\) 代指当前 \(a_i\) 所在的数列,其实 \(U,V\) 本质上是可以交换的所以第二种情况中我 将 \(a_{i+1}\) 拼到了 \(V\) 那么在下一次转移时,其实我还认为他是 \(U\)
也就是说,由于 \(U,V\) 之间没有本质区别,所以我们对于每次转移,称 \(a_i\) 所在序列为 \(U\) , \(f\) 所在序列为 \(V\)

然后最后答案的判断显然就是 \(f[n][n/2]\) 是否被更新过了
写到这里我才发现我的注释貌似是假的
但是我题解写清楚了就行

Code:

#include<bits/stdc++.h>
const int N=2005;
const int inf=1e9;
using namespace std;
int f[N][N];
int a[N],lim[N];
int n;
void init()
{
    for(int i=0;i<N;i++)for(int j=0;j<N;j++)f[i][j]=inf;
}
void  work()
{
    cin>>n;
    init();
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    int lim=n>>1;
    f[1][1]=-1;
    for(int i=1;i<n;i++)
    {
        for(int len_U=1,len_V;len_U<=min(lim,i);len_U++)
        {
            len_V=i-len_U;
            // U: .....a[i]
            // V: .....f[i][len_V]

            // U: .....a[i],a[i+1]
            // V: .....f[i+1][len_V]()
            if(a[i]<a[i+1])f[i+1][len_U+1]=min(f[i+1][len_U+1],f[i][len_U]);
            // U: .....a[i](f[i+1][len_U]),
            // V: .....f[i][len_V],a[i+1]
            if(f[i][len_U]<a[i+1])f[i+1][len_V+1]=min(f[i+1][len_V+1],a[i]);
        }
    }
    printf(f[n][lim]==inf ? "No!\n" : "Yes!\n");
}
int main()
{
    int T;
    cin>>T;
    while(T--)work();
    return 0;
}

标签:int,递增,len,P4728,序列,HNOI2009
From: https://www.cnblogs.com/LG017/p/18590476

相关文章

  • 代码随想录算法训练营第三十一天|leetcode56. 合并区间、leetcode738.单调递增的数字
    1leetcode56.合并区间题目链接:56.合并区间-力扣(LeetCode)文章链接:代码随想录视频链接:贪心算法,合并区间有细节!LeetCode:56.合并区间哔哩哔哩bilibili思路:其实很清楚,跟之前的方法差不多,但是自己写的时候就是有地方不会了,会不知道接下来的思路是什么1.1视频后的思路卡壳......
  • leetcode 1909. 删除一个元素使数组严格递增
    1909.删除一个元素使数组严格递增题解的做法都太复杂了,我的可能好理解一些classSolution{public:boolcanBeIncreasing(vector<int>&nums){intsize=nums.size();if(size==2)returntrue;boolisDown=false;//isDown表示是否出......
  • 代码随想录算法训练营第三十一天|leetcode56. 合并区间、leetcode738.单调递增的数字
    1leetcode56.合并区间题目链接:56.合并区间-力扣(LeetCode)文章链接:代码随想录视频链接:贪心算法,合并区间有细节!LeetCode:56.合并区间_哔哩哔哩_bilibili思路:其实很清楚,跟之前的方法差不多,但是自己写的时候就是有地方不会了,会不知道接下来的思路是什么1.1视频后的思路卡壳......
  • 最长递增子序列的个数 - 中等难度
    *************C++TOPIC:673.最长递增子序列的个数-力扣(LeetCode)*************先看题目:中等困难,之前做的是最长递增子序列,跟这个很像,先来复习一下找一下思路://这个逻辑比较的简单//就是说我直接定义dp数组,代表第i位最长递增数列的个数//遍历每一个元素//找到最......
  • 【贪心算法第五弹——300.最长递增子序列】
    目录1.题目解析题目来源测试用例2.算法原理3.实战代码代码解析注意本题还有一种动态规划的解决方法,贪心的方法就是从动态规划的方法总结而来,各位可以移步博主的另一篇博客先了解一下:动态规划-子序列问题——300.长递增子序列 1.题目解析题目来源300.最长递增......
  • 代码随想录算法训练营第二十五天|LeetCode491.递增子序列、46.全排列、47.全排列II、3
    前言打卡代码随想录算法训练营第49期第二十五天  ○(^皿^)っHiahiahia…首先十分推荐学算法的同学可以先了解一下代码随想录,可以在B站卡哥B站账号、代码随想录官方网站代码随想录了解,卡哥清晰易懂的算法教学让我直接果断关注,也十分有缘和第49期的训练营大家庭一起进步。今......
  • [MySQL]为什么主键最好是有序递增的
    为什么主键索引最好是有序递增的我们在建表的时候,都会默认将主键索引设置为自增的,具体为什么要这样做呢?又什么好处?InnoDB创建主键索引默认为聚簇索引,数据被存放在了B+Tree的叶子节点上。也就是说,同一个叶子节点内的各个数据是按主键顺序存放的,因此,每当有一条新的数据插入时......
  • 代码随想录刷题day25丨491.递增子序列 ,46.全排列 ,47.全排列 II
    代码随想录刷题day25丨491.递增子序列,46.全排列,47.全排列II1.题目1.1递增子序列题目链接:491.非递减子序列-力扣(LeetCode)视频讲解:回溯算法精讲,树层去重与树枝去重|LeetCode:491.递增子序列_哔哩哔哩_bilibili文档讲解:https://programmercarl.com/0491.%E9%80......
  • 300. 最长递增子序列(leetcode)
    https://leetcode.cn/problems/longest-increasing-subsequence/description/classSolution{publicintlengthOfLIS(int[]nums){//f[i]表示以第i个数为结尾的最长严格上升子序列//以倒数第二个数是多少来划分子集//f[i]=max(f[i-1],f[......
  • 每日OJ_牛客_最长递增子序列(dp/贪心模板)
    目录牛客_最长递增子序列(dp/贪心模板)解析代码牛客_最长递增子序列(dp/贪心模板)最长公共子序列__牛客网解析代码在一个序列中找最长递增子序列,动态规划的典型应用,下面是两个模版CISdp模板:#include<iostream>#include<vector>usingnamespacestd;intLIS(vect......