您的位置:首页 > 其它

hdu 4521 腾讯 小明序列

2014-02-23 21:15 190 查看
这题有两种算法,第一种是线段树,第二种是最长上升子序列(LIS)的变种。

先记下LIS的:

普通的LIS的O(nlogn)的算法是:维护一个栈,每次读到的元素和栈顶元素比较,如果大则入栈,否则二分查找第一个大于它的数,并替换(潜力增大),序列长度就是栈的长度。本题限定是间隔为d,解决办法是延迟入栈。避免中间一段的dp[i]受到影响。

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;

const int N=100005;
int data
,stack
,dp
;

int main(){
int n,d;//间隔d
while(cin>>n>>d){
for(int i=1;i<=n;++i)
cin>>data[i];
memset(dp,0,sizeof(dp));
memset(stack,0x3f,sizeof stack);
stack[0]=-1;
for(int i=1;i<=n;++i){
int k=lower_bound(stack,stack+n,data[i])-stack;
dp[i]=k;//栈顶下标 即 第i个元素结尾的长度
if(i-d > 0)//延迟入栈
stack[dp[i-d]]=min(stack[dp[i-d]],data[i-d]);
}
int ans=0;
for(int i=1;i<=n;++i)
ans=max(ans,dp[i]);
cout<<ans<<endl;
}
return 0;
}


线段树的做法基本相似,用len[val]表示小于值val结尾的最大长度,延迟更新。注意A[i]取值范围可能是0

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N=110000;
int A
,len[N*4],dp
;

inline int max(int a,int b){
return a>b?a:b;
}
void push_up(int rt){
len[rt]=max(len[rt*2],len[rt*2+1]);
}

void update(int p,int c,int l,int r,int rt){//单点更新 值p结尾的最大长度为c
if(l==r){
len[rt]=max(len[rt],c);
return;
}
int m=(l+r)>>1;
if(p<=m)
update(p,c,lson);
if(p>m)
update(p,c,rson);
push_up(rt);
}

int query(int a,int b,int l,int r,int rt){//查询 [0,A[i]-1]结尾的最大长度
if(a<=l&&b>=r)
return len[rt];
int rst=0,m=(l+r)>>1;
if(a<=m)
rst=max(rst,query(a,b,lson));
if(b>m)
rst=max(rst,query(a,b,rson));
return rst;
}

int main(){
int n,d;
while(~scanf("%d %d",&n,&d)){
int ans=0;
for(int i=1;i<=n;i++)
scanf("%d",&A[i]);
memset(len,0,sizeof len);
for(int i=1;i<=n;i++){//由于A[i]可能=0,所以+1
dp[i]=query(1,A[i]+1,1,N,1)+1;
if(i>d)
update(A[i-d]+2,dp[i-d],1,N,1);
if(dp[i]>ans)
ans=dp[i];
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: