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

链接:https://www.nowcoder.com/acm/contest/143/H
来源:牛客网
 

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

Kanade has an array a[1..n] , she define that an array b[1..m] is good if and only if it satisfy the following conditions:

  1. 1<=b[i]<=n

  2. b[i]<b[i+1] for every i between 1 and m-1

  3. a[b[i]] < a[b[i+1]] for every i between 1 and m-1

  4. m>0

Now you need to find the k-th smallest lexicographically good array.

输入描述:

The first line has two integer n,k

The second line has n integer a[i]

输出描述:

If there is no solution, just only output -1, else output two lines, the first line has an integer m, the second line has m integer b[i]

示例1

输入

复制

3 2
1 2 3

输出

复制

2
1 2

示例2

输入

复制

3 1000000000
1 2 3

输出

复制

-1

备注:

1<=n <= 5*10^5

1<=k<=10^(18)

1<=a[i]<=10^9

题目大意:求字典序第k小的递增序列(这里与洛谷上升序列相似,都是求下标字典序最小的序列)

解题思路:树状数组维护一个后缀和,dp[i],dp[i]表示以i开头的上升序列右多少个。那么dp[i]=1+sigma(j=[i+1,n])dp[j](a[j]>a[i])求和

输出的时候我们从前往后找,如果当前的dp[i]大于k说明当前位置满足条件,输出k--,如果当前dp[i]<k,则说明当前位置不在我们要的答案之中k-dp[i],最后如果k==0则说明存在这样的一个序列,否则不存在。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 500005
#define inf 1e18
#define lowb(x) x&-x
#define LL long long
LL sum[N];
int a[N],b[N],ans[N];
LL dp[N];
int n;
void add(int p,LL x)
{
    while(p)
    {
        sum[p]+=x;
        if(sum[p]>inf)sum[p]=inf;
        p-=lowb(p);
    }
}
 
LL query(int p)
{
    LL ans=0;
    while(p<=n)
    {
        ans+=sum[p];
        if(ans>inf) ans=inf;
        p+=lowb(p);
    }
    return ans;
}
int main()
{
    LL k;
    scanf("%d%lld",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    int cnt=unique(b+1,b+1+n)-b-1;
    for(int i=1;i<=n;i++)
    {
        a[i]=lower_bound(b+1,b+1+cnt,a[i])-b;
    }
    for(int i=n;i>=1;i--)
    {
        dp[i]=1+query(a[i]+1);
        add(a[i],dp[i]);
       // cout<<dp[i]<<endl;
    }
    int ss=1;
    int last=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>last)
        {
            if(dp[i]>=k)k--,ans[ss++]=i,last=a[i];
            else k-=dp[i];
        }
        if(k==0)break;
    }
    if(k)
    {
        printf("-1");
        return 0;
    }
    cout<<ss-1<<endl;
    for(int i=1;i<ss;i++)
    {
        printf("%d",ans[i]);
        if(i==ss-1)printf("\n");
        else printf(" ");
    }
}

参考博客:https://blog.csdn.net/sinat_35406909/article/details/81370130

猜你喜欢

转载自blog.csdn.net/weixin_40894017/article/details/81902432
今日推荐