9.9训练小结

题意:

给定一个序列(长度<=1e5), 要求从其中任选一段长度为L的子段并删除, 最后问你剩余序列的LIS(严格递增)为多少?

总结:

想到了枚举切割子段的起始点,进而也想到了预处理出以每一个元素为终点的LIS长度(前缀预处理)和以每一个元素为起点的LIS的长度(后缀预处理),进而也想到了从后往前枚举起始断点并维护一棵持久性权值线段树(持久性指在一次遍历过程中维护一颗线段树,每一个新的状态都可以依托现在的状态去构建(例如:D-Query)), 枚举前一段的终点,在线段树中查后一段中大于这个点中的最大LIS,然而总是wa,最后发现还是没注意一些细节。
(1)后缀预处理以每一个元素为起点的LIS的长度时,buf[]数组的初值应该设为-INF而不是0,因为初始序列可能有负值
(2)只考虑了以前段中的某元素为终点选一段,然后再在后半段中找拼接的,但是忽略了LIS只出现在前半段或后半段的情况, 即以后在解决其他问题时一定要留意有什么可能的特殊情况。
(3)L=0时不是直接取pre[n]做为答案,而是以max{pre[1],pre[2],pre[3],..,pre[n]}作为答案,即以后在解决dp问题时,一定注意"状态的定义"与"最优值"的关联(诸如:dp[i]是前1~i段中的最值,还是以i为结尾的段的最值)。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define mid ((l+r)>>1)
const int maxn=1e5+10;
const int INF=0x3f3f3f3f; 
int a[maxn],ind[maxn],m;
int n,L,pre[maxn],suf[maxn],buf[maxn];
int maxx[maxn<<2];
void init(){
    int i,j;
    for(i=1;i<=n;i++) buf[i]=INF;
    for(i=1;i<=n;i++){
        j=lower_bound(buf+1,buf+n+1,a[i])-buf;
        buf[j]=a[i]; pre[i]=j;
    }
    for(i=1;i<=n;i++) buf[i]=-INF;
    for(i=n;i>=1;i--){
        j=upper_bound(buf+i,buf+n+1,a[i])-buf-1;
        buf[j]=a[i]; suf[i]=n+1-j;
    }
}
void build(int l,int r,int u){
    maxx[u]=0;
    if(l==r) return ;
    build(l,mid,u<<1); build(mid+1,r,u<<1|1); 
}
void update(int p,int v,int l,int r,int u){
    if(l==r) {maxx[u]=max(maxx[u],v); return ;}
    p<=mid ? update(p,v,l,mid,u<<1) : update(p,v,mid+1,r,u<<1|1);
    maxx[u]=max(maxx[u<<1],maxx[u<<1|1]);
}
int query(int pl,int pr,int l,int r,int u){
    if(pl>pr) return 0; //注意此处还要判断查询区间不合法的情形 !!! 
    if(pl<=l&&r<=pr) return maxx[u];
    int res=0;
    if(pl<=mid) res=query(pl,pr,l,mid,u<<1);
    if(pr>mid) res=max(res,query(pl,pr,mid+1,r,u<<1|1));
    return res;
}
int main(){
    int t,i,j,k,id,ans,cnt=0;
    cin>>t;
    for(;t;t--){
        scanf("%d%d",&n,&L); m=0;
        for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
            ind[++m]=a[i];
        }sort(ind+1,ind+m+1); m=unique(ind+1,ind+m+1)-ind-1;
        init(); ans=0;
        if(L==0) ans=*max_element(pre+1,pre+n+1);
        else {
            build(1,m,1);
            for(i=n-L;i>=1;i--){
                id=lower_bound(ind+1,ind+m+1,a[i])-ind;
                ans=max(ans,query(id+1,m,1,m,1)+pre[i]);
                if(i+L<=n) {
                    id=lower_bound(ind+1,ind+m+1,a[i+L])-ind;
                    update(id,suf[i+L],1,m,1);
                }
            }
            for(i=L+1;i<=n;i++) ans=max(ans,suf[i]);
        }
        printf("Case #%d: %d\n",++cnt,ans);
    } 
    return 0;
}
全部评论

相关推荐

感性的干饭人在线蹲牛友:🐮 应该是在嘉定这边叭,禾赛大楼挺好看的
点赞 评论 收藏
分享
10-13 17:47
门头沟学院 Java
wulala.god:图一那个善我面过,老板网上找的题库面的
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务