[HAOI 2007]上升序列

59 篇文章 0 订阅
49 篇文章 0 订阅

题目描述:

QAQ…

题目分析:

设 F[i] 为 以 i 为开头最大的上升子序列长度 可以 NlogN N l o g N 求,不再概述了
然后对于每个查询,我们 O(n) O ( n ) 去扫 当F[i]>=k 并且大于上一个数的时候,这个数即为我们要求的数列项之一,由于我们是从前往后扫的,所以字典序有保证,不要忘了把长度减小1
线段树完全可以用树状数组代替,然后我闲得慌...

题目链接:

BZOJ 1046
Luogu 2215

Ac 代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
const int maxm=11000;
int hash[maxm],a[maxm],dp[maxm];
int maxi[maxm<<2];
int n,m,maxlen;
void insert(int o,int l,int r,int ind,int val)
{
    if(l>=r) return (void)(maxi[o]=val);
    int mid=(l+r)>>1;
    ind<=mid?insert((o<<1),l,mid,ind,val):insert((o<<1)|1,mid+1,r,ind,val);
    maxi[o]=std::max(maxi[(o<<1)],maxi[(o<<1)|1]);
}
int ask(int o,int l,int r,int ql,int qr)
{
    if(r<ql||l>qr) return 0;
    if(ql<=l&&r<=qr) return maxi[o];
    int mid=(l+r)>>1;
    int ans=0;
    if(ql<=mid) ans=std::max(ans,ask((o<<1),l,mid,ql,qr));
    if(qr>mid) ans=std::max(ans,ask((o<<1)|1,mid+1,r,ql,qr));
    return ans;
}
inline void slove(int k)
{

    int maxx=0;
    for(int i=1;i<=n;i++)
    if(dp[i]>=k&&a[i]>maxx)
    {
        printf("%d ",hash[a[i]]);
        maxx=a[i];
        k--;
        if(k==0) {puts("");return;}
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),hash[i]=a[i];
    std::sort(hash+1,hash+n+1);
    int t=std::unique(hash+1,hash+n+1)-hash-1;
    for(int i=1;i<=n;i++) a[i]=std::lower_bound(hash+1,hash+t+1,a[i])-hash;
    for(int i=n;i>=1;i--) dp[i]=ask(1,1,t,a[i]+1,t)+1,insert(1,1,t,a[i],dp[i]),maxlen=std::max(maxlen,dp[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int k;
        scanf("%d",&k);
        if(k>maxlen) puts("Impossible");
        else slove(k);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值