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

来源:互联网 发布:仿京东商城html源码 编辑:程序博客网 时间:2024/06/03 06:08

题目大意:给定一个序列长度为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 999999999int 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 999999999int 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;}









0 0