hdu 5489 LIS变形(删掉连续区间)

题目大意:给定一个序列长度为n,从中去掉长度为l的连续的序列,求剩余序列中的LIS,去掉的序列起始位置随意


思路:LIS变形,只要枚举去掉的所有区间就可以了,最大长度等于以区间右边第一个元素开始的LIS+区间左边的小于右边第一个元素的LIS-1.右边的直接逆序求LIS即可。

左边的常规LIS。左边的需要计算arr[i+l]在a[1……i]中的最大LIS就是我说的那个加法的后半部分。


ps:逆序求LIS有两种方法,第一种是将arr数组的所有元素取反,然后求。另外一种就是直接开始求,用upper_bound。本来前一天就该过得,但是初始化时的INF开小了,为99999999 ,tmp数组初始化也小了为0,正确的应该是999999999 , -999999999.

代码1:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>

using namespace std;
#define maxn 500005
#define MOD 1000000007
#define mem(a , b) memset(a , b , sizeof(a))
#define LL long long
#define xxx 1000000005
#define INF 999999999

int arr[maxn];
int b[maxn];
int dp[maxn] ;
int g[maxn];

int main()
{
    int t;
    int ncase = 1;
    scanf("%d" , &t);
    while(t--)
    {
        int n , l , k;
        scanf("%d %d" , &n  , &l);
        for(int i = 1 ; i <= n ; i ++)
        {
            scanf("%d" , &arr[i]);
            b[i] = -arr[i];
        }
        mem(dp , 0);
        for(int i = 0 ; i <= n ; i ++) g[i] = INF;
       // mem(g , 0x7f);
        for(int i = n ; i > l ; i --)   //逆序LIS
        {
            k = lower_bound(g+1 , g+n+1 , b[i]) - g;
            dp[i] = k;
            g[k] = b[i];
        }
       // mem(g , 0x7f);
       for(int i = 0 ; i <= n ; i ++) g[i] = INF;
        int ans = 0 , maxlen = 0 ;
        for(int i = 1 ; i <= n - l ; i ++)
        {
            k = lower_bound(g+1 , g+n+1 , arr[i+l]) - g;
            ans = max(ans , k + dp[i+l] - 1);   //重算了i+l位置的元素,所以需要减1
            k = lower_bound(g+1 , g+n+1 , arr[i]) - g;
            g[k] = arr[i];
            maxlen = max(maxlen , k);
        }
        ans = max(ans , maxlen);   //区间是最后的一段,上面个的代码不能比较,需要单独比较
        printf("Case #%d: %d\n" , ncase++ , ans);
    }
    return 0;
}

代码2:


#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>

using namespace std;
#define maxn 500005
#define MOD 1000000007
#define mem(a , b) memset(a , b , sizeof(a))
#define LL long long
#define xxx 1000000005
#define INF 999999999

int dp[maxn];
int dp2[maxn];
int g[maxn];
int tmp[maxn];
int arr[maxn];
int per[maxn];

int main()
{
    int t;
    int ncase = 1;
    scanf("%d" , &t);
    while(t--)
    {
        int n , l;
        scanf("%d %d" , &n  , &l);
        for(int i = 1 ; i <= n ; i ++)
        {
            scanf("%d" , &arr[i]);
        }
        for(int i = 0 ; i <= n ; i ++) g[i] = INF ,tmp[i] = -INF;
        mem(dp,0);
        mem(dp2,0);
        mem(per , 0);
        int ans = 0;
        int len = 0;
        for(int i = 1 ; i <= n - l; i ++)
        {
            if(i + l <= n)   ///求区间右边第一个数在左边的位置
            {
                int k2 = lower_bound(g + 1, g + n + 1 , arr[i+l]) - g;
                per[i+l] = k2;

            }
            int k = lower_bound(g +1, g + n +1, arr[i]) - g;
            dp[i] = k;
            g[k] = arr[i];
            len = max(len , k);
        }
        ans = max(per[n] , len);
        for(int i = n; i > l ; i --)   //求逆序LIS
        {
            int k = upper_bound(tmp + 1, tmp + n + 1, arr[i]) - tmp;
            dp2[i] =  n+1 - (k - 1) ;
            tmp[k -1] = arr[i];
        }
        for(int i = l + 1 ; i <= n ; i ++)
        {
            int res = per[i] + dp2[i] - 1;
            ans = max(res , ans);
        }
        ans = max(ans , dp[n-l]);
        printf("Case #%d: %d\n" , ncase++ , ans);
    }
    return 0;
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值