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

subseq

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

题目描述

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

题意:给出一个数组a,求的一个第k小且符合b[i]<b[i+1] a[b[i]]<b[b[i+1]]的序列
思路:我们可以考虑每个点的贡献 如果 a序列为 1 2 3
我们可以写出 1 ,1 2,1 3, 1 2 3 四种以1开头的符合题意的序列b
分析下样例1:我们能的到如下序列b, 1, 1 2, 1 2 3,1 3, 2 , 2 3,3 字典序第2小 显然是1 2我们即可输出 1 2
考虑我们怎么维护树状数组,我们离散化后,我们维护的是这个点能给其他点添加序列 比如3 能给1添加两次贡献,能 2添加1次 给3添加1次
我们从a[n]遍历到a[1],我插入前需要查询此点的贡献。
继续分析样例:
3离散后也是,3,我们查询比3大的是否有贡献,3为第一个插入的数 贡献为它自己1 插入到树状数组
继续 2离散后是2,我们查询比2大的是否有贡献,显然3之前我们已经插入了 ,此时2的贡献为1+1(3的贡献 插入到树状数组
最后 1离散后是1,我们查询比1大的是否有贡献,显然2和3我们之前已经插入了,此时1的贡献为1+2(2的贡献)+1(3的贡献) 然后插入进去
然后我们只需要慢慢求下标就好了,k>f[i](a[i]的贡献)我们就不需要用到a[i]这个点,k<=f[i]时我们就只要慢慢求出和a[i]构成的序列即可
在维护的时候如果贡献大于1e18我们就只需要讲贡献改为1e18就行 k的取值最大1e18

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=6e5+10;
const long long inf=1e18;
ll a[maxn],f[maxn],tree[maxn],N;
vector<ll> v;
int getid(ll x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}
int lowbit(int x){return x&(-x);}
void add(int x,ll val)
{
    for(; x; x-=lowbit(x))
    {
        tree[x]+=val;
        if(tree[x]>=inf) tree[x]=inf;
    }
}
ll query(int x)
{
    ll ans=0;
    for(; x<=N; x+=lowbit(x))
    {
        ans+=tree[x];
        if(ans>=inf) ans=inf;
    }
    return ans;
}
int main()
{
    int n;
    ll k;
    scanf("%d %lld",&n,&k);
    for(int i=1; i<=n; i++)
    {
        scanf("%lld",&a[i]);
        v.push_back(a[i]);
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    N=v.size();
    for(int i=n; i>=1; i--)
    {
        f[i]=query(getid(a[i])+1)+1;
        add(getid(a[i]),f[i]);
    }
    ll last=0;
    vector<int> V;
    for(int i=1; i<=n; i++)
    {
        if(k==0) break;
        if(a[i]>last)
        {
            if(k<=f[i])
            {
                k--;
                V.push_back(i);
                last=a[i];
            }
            else
            {
                k-=f[i];
            }
        }

    }
    if(k)
        return 0*puts("-1");
    printf("%d\n",V.size());
    for(int i=0; i<V.size(); i++)
    {
        printf("%d%c",V[i]," \n"[i==V.size()-1]);
    }
    return 0;

}
View Code

 




PS:摸鱼怪的博客分享,欢迎感谢各路大牛的指点~
posted @ 2018-08-03 11:07  MengX  阅读(284)  评论(0编辑  收藏  举报

梦想不是空想