您的位置:首页 > 其它

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

2016-01-04 17:17 369 查看
题目大意:给定一个序列长度为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
, 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: