牛客网暑期ACM多校训练营(第五场)H-subseq

                                                H-subseq                                             

 

传送门

题意:稍微转化一下题意就可以发现这题问的其实就是a序列中字典序第k大的递增子序列.

为了解决这道题,我们可以定义一个dp[i]表示从i到后面的所有的递增自序列个数的总和,这个dp用树状数组就可以很简单的处理出来,但是要注意的是,这题的N的范围为5e5,那么dp[1]在极端情况下比如a本身就是一个递增序列的时候,肯定会爆long long

这个时候就要对树状数组稍作处理,因为k最大也只有1e18,所以我们将dp的最大值限定为1e18就够了

在处理出dp之后,我们从左往右找,假设我们目前已经取了m个数字,第m个数字为x,那么我们就要保证对于下一个取的数字j总是存在a[x]<a[j].

只要对于i位置dp[i]>=k,那么这个i肯定是我们要取的位置,否则更新k=k-dp[i]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+5;
int a[maxn],b[maxn];
int sc[maxn];
ll bit[maxn];
ll dp[maxn];
int ans[maxn];
int lowbit(int x)
{
    return x&-x;
}
void add(int x,ll v)
{
    while(x)
    {
        bit[x]+=v;
        if(bit[x]>1e18) bit[x]=1e18;
        x-=lowbit(x);
    }
}
ll sum(int x)
{
    ll res=0;
    while(x<maxn) res+=bit[x],res=min(res,1000000000000000000ll),x+=lowbit(x);
    return res;
}
int main()
{
    int n;
    ll k;
    scanf("%d%lld",&n,&k);
    for(int i=1; i<=n; i++) scanf("%d",&a[i]),b[i]=a[i],bit[i]=0;
    sort(b+1,b+n+1);
    int pos=unique(b+1,b+n+1)-b;
    for(int i=1; i<=n; i++) sc[i]=lower_bound(b+1,b+pos+1,a[i])-b;
    dp[n]=1;
    add(sc[n],1);
    for(int i=n-1; i>=1; i--)
    {
        dp[i]=sum(sc[i]+1)+1;
        add(sc[i],dp[i]);
    }
    int p=0;
    for(int i=1; i<=n; i++)
    {
        if(k<=0) break;
        if(a[i]>a[ans[p]])
        {
            if(k<=dp[i]) ans[++p]=i,k--;
            else k-=dp[i];
        }
    }
    if(k) return printf("-1\n")*0;
    printf("%d\n",p);
    for(int i=1; i<=p; i++) printf("%d ",ans[i]);
    printf("\n");
}

猜你喜欢

转载自blog.csdn.net/Murphyc/article/details/81386238
今日推荐