您的位置:首页 > 其它

HDU 5489 Removed Interval(2015合肥站网赛1006,DP+树状数组)

2015-09-28 21:18 295 查看
当时写的时候并不会,一直想不通一个问题,每次删除的区间从L,R->L+1,R+1的时候,如何维护整个剩余序列的LIS。太弱。。。。

赛后才搞懂这个问题,就是一个dp的问题吧。

dp1[i]表示以num[i]开头的LIS。

dp2[i]表示以num[i]结尾的LIS。

dp[i]表示以分割出来的第二段num[i]为开头的LIS+第一段中的序列的最大值

我们设删除的区间长度为d

那么dp[i] = dp1[i] + max(dp2[j] | j < i -d && num[j] < num[i])。

因为要在一个logn的复杂度搞定max的查找,那么用线段树就可以搞定了。就是一个普通的LIS过程,复杂度是nlogn。

我们最后要找的答案就是dp[i]的最大值o(n)搞定。

所以这道题最终的复杂度就是nlogn。

注意点:如果删除的区间是从第一个开始或者正好最后一个数结束的时候,那么我们这个区间就是一段了,没有第二段了,这个时候特判一下就好了。

下面附上代码:

#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y)  for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define MAXN 100010

using namespace std;

int dp[MAXN];
int num[MAXN],con[MAXN];
int c[MAXN];
int cnt,n,d;
map <int,int> mat;

int lowbit(int x)   {return x & (-x);}

int Query(int x){
int ans = 0;
while(x){
ans = max(ans,c[x]);
x -= lowbit(x);
}
return ans;
}

void Modify(int x,int val){
while(x <= n){
c[x] = max(c[x],val);
x += lowbit(x);
}
}

void init(){
memset(c,0,sizeof(c));
FOR(i,0,cnt){
int val = Query(con[i]-1);
dp[cnt-1-i] = val + 1;
Modify(con[i],dp[cnt-1-i]);
}
}

int work(){
memset(c,0,sizeof(c));
int ans;
ans = (d == cnt) ? 0 : dp[d];
FOR(i,1,cnt){
int r = i + d;
if(r > cnt)   break;
if(r == cnt)    {
int val = Query(mat[num[i-1]]-1)+1;
Modify(mat[num[i-1]],val);
int res = Query(n);
ans = max(ans,res);
break;
}
int val = Query(mat[num[i-1]]-1)+1;
Modify(mat[num[i-1]],val);
int res = Query(mat[num[r]]-1) + dp[r];
ans = max(res,ans);
}
return ans;
}

int main()
{
//freopen("test.in","r",stdin);
int T,tCase = 0;
scanf("%d",&T);
while(T--){
printf("Case #%d: ",++tCase);
scanf("%d%d",&cnt,&d);
FOR(i,0,cnt)  scanf("%d",&num[i]),con[i] = num[i];
sort(con,con+cnt);
n = 0;
mat[con[0]] = ++n;
FOR(i,1,cnt)    if(con[i] != con[i-1])  mat[con[i]] = ++n;
FOR(i,0,cnt)    con[i] = n+1-mat[num[cnt-1-i]];
init();
printf("%d\n",work());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: