COJ_2040_成群的触手(双向dp)

本文介绍了一个有趣的编程挑战,即寻找特定长度的浪漫序列。浪漫序列是指序列中的元素先递增后递减,且相邻元素不相等。文章提供了一个高效的算法实现,通过双向最长严格递增子序列的方法,在O(nlogn)的时间复杂度内解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

I. 成群的触手

Time Limit: 1000ms Memory Limit: 65536KB
饭团学长终于成功的约了漂亮的大姐姐,但是漂亮大姐姐来约会的路上要经过一片沼泽地,为了能让漂亮大姐姐顺利渡过沼泽,饭团学长发现沼泽地里生长着成群的触手,所以决定利用触手搭桥。 但是触手们也有自己的脾气,他们已经排成了一序列,并且每个触手有着不同的高度aiai。为了表示浪漫,学长决定从中选出m个触手,使选出的触手满足长度从低到高再从高到低,且选出的相邻触手长度不等(例如:1 2 3 2 1是长度为5浪漫的序列,1 2 3 则不是浪漫的序列,同理3 2 1也不是浪漫的序列 。注意1 2 1 2也不是浪漫的序列,因为其长度是从低到高再到低再到高,学长认为这会让漂亮姐姐觉得不舒服)。但是学长一心只想着漂亮大姐姐无心写代码,请你帮助下颓废的学长吧。

Input

第一行一个数TT,代表有(T<100)(T<100)个样例; 每个样例的第一行输入两个整数nnmm用空格分隔,nn<103n(n<103)代表触手的数量,mm(m<nm<n)代表希望的浪漫序列长度。 接下来一行 有nn 个数aiai<109ai(ai<109),用空格分隔 。

Output

如果能有这样一个长度为mm的浪漫序列,输出YES。否则输出NO。

Sample Input

3
3 3
1 2 3
3 3
3 2 1
5 4
1 2 3 2 1

Sample Output

NO
NO
YES

Hint

例如,第三组样例,m=4,可构成题目描述中的“从矮到高再从高到矮的子序列”的有:(1,2,1),(1,3,2),(1,3,1),(2,3,2),(2,3,1),(1,2,3,2),(1,2,3,1),(1,3,2,1),(2,3,2,1),(1,2,3,2,1) 在这些序列中显然有长度为4的,所以输出“YES”。

















































双向最长严格递增子序列,双向dp,这里给出O(nlogn)的算法,因为直接dp是O(n^2),这里用dp当然能过,因为最长也就1000个点,但如果最长是10W个点这里用数组模拟栈+贪心的优势就将体现出来。

关于这种方法求LIS(Longest Increasing Subsequence)可以参照我的另一篇博客:

关键是这里用了d数组去记录,d[i]表示以a[i]为终点的最长增加子序列的长度,这样正反一扫,最后能找到一个d1[i] + d2[i] - 1 >= m 则满足情况 交点算了两次故减一。


#include <bits/stdc++.h>

using namespace std;
const int MAXN = 1000 + 7;
const int inf = 1e9 + 7;
int n, m, a[MAXN], d1[MAXN], d2[MAXN], stimulate_stack1[MAXN], stimulate_stack2[MAXN];

int main()
{
        int t;
        scanf("%d", &t);
        while (t--)
        {
                bool flag = false;
                memset(a, 0, sizeof(a));
                memset(d1, 0, sizeof(d1));
                memset(d2, 0, sizeof(d2));
                scanf("%d%d", &n, &m);
                for (int i = 1; i <= n; ++i)
                {
                        scanf("%d", &a[i]);
                        stimulate_stack1[i] = stimulate_stack2[i] =  inf;
                }
                for (int i = 1; i <= n; ++i)
                {
                        int k1 = lower_bound(stimulate_stack1 + 1, stimulate_stack1 + n + 1, a[i]) - stimulate_stack1;
                        d1[i] = k1;
                        stimulate_stack1[k1] = a[i];

                        int k2 = lower_bound(stimulate_stack2 + 1, stimulate_stack2 + n + 1, a[n-i+1]) - stimulate_stack2;
                        d2[n-i+1] = k2;
                        stimulate_stack2[k2] = a[n-i+1];
                }
                for(int i = 1; i <= n; ++i)
                {
                        if(d1[i] + d2[i] - 1 >= m && (d1[i] > 1 && d2[i] > 1))
                        {
                               flag = true;
                               break;
                        }

                }
                if(flag)
                        cout << "YES" << endl;
                else
                        cout << "NO" << endl;
        }
        return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值